併發編程重點:
1
2
3
4
5
6
7
|
併發編程:線程、進程、隊列、IO多路模型
操做系統工做原理介紹、線程、進程演化史、特色、區別、互斥鎖、信號、
事件、join、GIL、進程間通訊、管道、隊列。
生產者消息者模型、異步模型、IO多路複用模型、select\poll\epoll 高性
能IO模型源碼實例解析、高併發FTP server開發
|
一、請寫一個包含10個線程的程序,主線程必須等待每個子線程執行完成以後才結束執行,每個子線程執行的時候都須要打印當前線程名、當前活躍線程數量;html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
from
threading
import
Thread,currentThread,activeCount
import
time
def
task(n):
print
(
'線程名:%s----%s'
%
(currentThread().name,n))
time.sleep(
1
)
print
(
'數量:%s'
%
activeCount())
if
__name__
=
=
"__main__"
:
t_li
=
[]
for
i
in
range
(
10
):
t
=
Thread(target
=
task,args
=
(i,))
t.start()
t_li.append(t)
for
t
in
t_li:
t.join()
print
(
'主,end----'
)
|
二、請寫一個包含10個線程的程序,並給每個子線程都建立名爲"name"的線程私有變量,變量值爲「james」;python
1
2
3
4
5
6
7
8
9
10
11
|
from
threading
import
Thread
def
task(name):
print
(
'%s is running'
%
name)
print
(
'end ---'
)
if
__name__
=
=
"__main__"
:
for
i
in
range
(
10
):
t
=
Thread(target
=
task,args
=
(
'james_%s'
%
i,))
t.start()
print
(
'主 end ---'
)
|
三、請使用協程寫一個消費者生產者模型;mysql
協程知識點:http://www.javashuo.com/article/p-adknkdvb-ct.htmlsql
協程:單線程下,沒法利用多核,能夠是一個程序開多個進程,每一個進程開啓多個線程,每隔線程開啓協程;數據庫
協程指的是單個線程,於是一旦協程出現阻塞,將會阻塞整個線程。編程
1
2
3
4
5
6
7
8
9
10
11
12
13
|
def
consumer():
while
True
:
x
=
yield
print
(
'消費:'
, x)
def
producter():
c
=
consumer()
next
(c)
for
i
in
range
(
10
):
print
(
'生產:'
, i)
c.send(i)
producter()
|
四、寫一個程序,包含十個線程,子線程必須等待主線程sleep 10秒鐘以後才執行,並打印當前時間;性能優化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
from
threading
import
Thread,Event
import
time
import
datetime
def
task():
# while not event.is_set():
# print('...')
print
(
'...'
)
event.wait(
10
)
print
(
'time:'
,datetime.datetime.now())
if
__name__
=
=
'__main__'
:
event
=
Event()
for
i
in
range
(
10
):
t
=
Thread(target
=
task)
t.start()
time.sleep(
10
)
event.
set
()
|
五、寫一個程序,包含十個線程,同時只能有五個子線程並行執行;服務器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
from
threading
import
Thread,Semaphore,currentThread
import
time
def
task(n):
sm.acquire()
print
(
'%s---'
%
n,currentThread().name)
time.sleep(
1
)
print
(
'end----'
)
sm.release()
if
__name__
=
=
'__main__'
:
sm
=
Semaphore(
5
)
for
i
in
range
(
10
):
t
=
Thread(target
=
task,args
=
(i,))
t.start()
|
六、寫一個程序 ,包含一個名爲hello的函數,函數的功能是打印字符串「Hello, World!」,該函數必須在程序執行30秒以後纔開始執行(不能使用time.sleep());網絡
1
2
3
4
5
6
7
|
from
threading
import
Timer
def
hello(name):
print
(
'%s say '
%
name,
'Hello World!'
)
if
__name__
=
=
"__main__"
:
t
=
Timer(
5
,hello,args
=
(
'james'
,))
t.start()
|
七、寫一個程序,利用queue實現進程間通訊;多線程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
from
multiprocessing
import
Process,Queue,current_process
import
time
def
consumer(q):
while
True
:
res
=
q.get()
if
not
res:
break
print
(
'消費了:'
,res,
'--'
,current_process().name)
def
producter(q):
for
i
in
range
(
5
):
print
(
'生產:'
,i)
time.sleep(
1
)
q.put(i)
if
__name__
=
=
"__main__"
:
q
=
Queue()
p1
=
Process(target
=
producter,args
=
(q,))
c1
=
Process(target
=
consumer,args
=
(q,))
c2
=
Process(target
=
consumer,args
=
(q,))
p1.start()
c1.start()
c2.start()
p1.join()
q.put(
None
)
q.put(
None
)
print
(
'主'
)
# JoinableQueue
from
multiprocessing
import
Process,JoinableQueue,current_process
import
time
def
consumer(q):
while
True
:
res
=
q.get()
print
(
'消費了:'
,res,
'--'
,current_process().name)
q.task_done()
def
producter(q):
for
i
in
range
(
5
):
print
(
'生產:'
,i,
'--'
,current_process().name)
time.sleep(
1
)
q.put(i)
q.join()
if
__name__
=
=
"__main__"
:
q
=
JoinableQueue()
p1
=
Process(target
=
producter,args
=
(q,))
p2
=
Process(target
=
producter, args
=
(q,))
c1
=
Process(target
=
consumer,args
=
(q,))
c2
=
Process(target
=
consumer,args
=
(q,))
p1.start()
p2.start()
c1.daemon
=
True
c2.daemon
=
True
c1.start()
c2.start()
p1.join()
p2.join()
print
(
'主'
)
|
八、寫一個程序,利用pipe實現進程間通訊;
1
2
3
4
5
6
7
8
9
10
11
|
from
multiprocessing
import
Process,Pipe
def
task(conn):
conn.send(
'hello world'
)
conn.close()
if
__name__
=
=
"__main__"
:
parent_conn,child_conn
=
Pipe()
p
=
Process(target
=
task,args
=
(child_conn,))
p.start()
p.join()
print
(parent_conn.recv())
|
九、使用selectors模塊建立一個處理客戶端消息的服務器程序;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
# server blocking IO
import
socket
server
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((
'127.0.0.1'
,
8080
))
server.listen(
5
)
while
True
:
conn,addr
=
server.accept()
print
(addr)
while
True
:
try
:
data
=
conn.recv(
1024
)
if
not
data:
break
conn.send(data.upper())
except
Exception as e:
print
(e)
break
# server IO多路複用 selectors 會根據操做系統選擇select poll epoll
import
socket
import
selectors
sel
=
selectors.DefaultSelector()
def
accept(server_fileobj,mask):
conn,addr
=
server_fileobj.accept()
print
(addr)
sel.register(conn,selectors.EVENT_READ,read)
def
read(conn,mask):
try
:
data
=
conn.recv(
1024
)
if
not
data:
print
(
'closing..'
,conn)
sel.unregister(conn)
conn.close()
return
conn.send(data.upper())
except
Exception:
print
(
'closeing...'
,conn)
sel.unregister(conn)
conn.close()
server_fileobj
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_fileobj.bind((
'127.0.0.1'
,
8080
))
server_fileobj.listen(
5
)
server_fileobj.setblocking(
False
)
sel.register(server_fileobj,selectors.EVENT_READ,accept)
while
True
:
events
=
sel.select()
for
sel_obj,mask
in
events:
callback
=
sel_obj.data
callback(sel_obj.fileobj,mask)
# client
# -*- coding:utf-8 -*-
import
socket
client
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect((
'127.0.0.1'
,
8080
))
while
True
:
msg
=
input
(
'>>>:'
).strip()
if
not
msg:
continue
client.send(msg.encode(
'utf-8'
))
data
=
client.recv(
1024
)
print
(data.decode(
'utf-8'
))
|
十、使用socketserver建立服務器程序時,若是使用fork或者線程服務器,一個潛在的問題是,惡意的程序可能會發送大量的請求致使服務器崩潰,請寫一個程序,避免此類問題;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# server socketserver 模塊內部使用IO多路複用 和多進程/多線程
import
socketserver
class
Handler(socketserver.BaseRequestHandler):
def
handle(
self
):
print
(
'new connection:'
,
self
.client_address)
while
True
:
try
:
data
=
self
.request.recv(
1024
)
if
not
data:
break
print
(
'client data:'
,data.decode())
self
.request.send(data.upper())
except
Exception as e:
print
(e)
break
if
__name__
=
=
"__main__"
:
server
=
socketserver.ThreadingTCPServer((
'127.0.0.1'
,
8080
),Handler)
server.serve_forever()
|
十一、請使用asyncio實現一個socket服務器端程序;
十二、寫一個程序,使用socketserver模塊,實現一個支持同時處理多個客戶端請求的服務器,要求每次啓動一個新線程處理客戶端請求;
1
2
3
4
5
6
7
8
9
|
socketserver模塊類介紹
SocketServer內部使用 IO多路複用 以及 「多線程」 和 「多進程」 ,
從而實現併發處理多個客戶端請求的Socket服務端。即:每一個客戶端請求
鏈接到服務器時,Socket服務端都會在服務器是建立一個「線程」或者「進 程」
專門負責處理當前客戶端的全部請求。
socketserver模塊能夠簡化網絡服務器的編寫,python把網絡服務抽
象成兩個主要的類,一個是server類,用於處理鏈接相關的網絡操做,另外一個
是RequestHandler類,用於處理數據相關的操做。而且提供兩個Mixln類,
用於擴展server,實現多進程或者多線程。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import
socketserver
import
threading
class
MyServer(socketserver.BaseRequestHandler):
def
handle(
self
):
while
True
:
self
.data
=
self
.request.recv(
1024
).decode()
print
(
self
.data)
self
.request.send(
self
.data.upper().encode())
if
__name__
=
=
'__main__'
:
server
=
socketserver.ThreadingTCPServer((
'127.0.0.1'
,
9999
), MyServer)
t
=
threading.Thread(target
=
server.serve_forever)
t.start()
|
數據庫重點:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
1
、數據庫介紹、類型、特性
2
、MySQL數據庫安裝、鏈接、啓動、中止
3
、表字段類型介紹、主鍵約束、表建立語句
4
、經常使用增刪改查語句、分組、聚合
5
、外鍵管理、unique字段、表結構修改語法
6
、跨表查詢,inner join、left join、right join、full join語法
7
、複雜SQL語句如group by、子查詢、函數的使用
8
、索引原理及做用、普通索引、多列索引、惟一索引、全文索引等
9
、基於
hash
&b
+
樹索引的實現原理,索引的優缺點剖析
10
、事務原理,ACID特性,應用場景講解
11
、事務回滾
12
、觸發器的特性,應用場景
13
、觸發器的增刪改查方法
14
、存儲過程的做用及應用場景
15
、建立存儲過程,參數傳遞,流程控制語句
if
\
while
\repeat\loop等,動態SQL的建立
16
、視圖的做用及使用場景,視圖的增刪改查
17
、數據庫權限管理,用戶管理
18
、數據庫備份命令及工具講解
19
、基於不一樣業務的數據庫表結構設計、性能優化案例
20
、pymysql模塊介紹和使用
|
修改表結構的語法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
語法:
1.
修改表名
ALTER TABLE 表名
RENAME 新表名;
2.
增長字段
ALTER TABLE 表名
ADD 字段名 數據類型 [完整性約束條件…],
ADD 字段名 數據類型 [完整性約束條件…];
ALTER TABLE 表名
ADD 字段名 數據類型 [完整性約束條件…] FIRST;
ALTER TABLE 表名
ADD 字段名 數據類型 [完整性約束條件…] AFTER 字段名;
3.
刪除字段
ALTER TABLE 表名
DROP 字段名;
4.
修改字段
ALTER TABLE 表名
MODIFY 字段名 數據類型 [完整性約束條件…];
ALTER TABLE 表名
CHANGE 舊字段名 新字段名 舊數據類型 [完整性約束條件…];
ALTER TABLE 表名
CHANGE 舊字段名 新字段名 新數據類型 [完整性約束條件…];
|
一、建立一個表student,包含ID(學生學號),sname(學生姓名),gender(性別),credit(信用卡號),四個字段,要求:ID是主鍵,且值自動遞增,sname是可變長字符類型,gender是枚舉類型, credit是可變長字符類型;
1
2
3
4
5
6
|
create table student(
ID
int
primary key auto_increment,
sname varchar(
16
)
not
null,
gender enum(
'male'
,
'female'
)
not
null default
'female'
,
credit varchar(
32
)
);
|
二、在上面的student表中增長一個名爲class_id的外鍵,外鍵引用class表的cid字段;
1
2
3
4
5
6
7
|
create table
class
(
cid
int
primary key auto_increment,
cname varchar(
16
)
not
null
);
alter table student add class_id
int
not
null;
alter table student add foreign key(class_id) references
class
(cid) on delete cascade on update cascade;
|
三、向該表新增一條數據,ID爲1,學生姓名爲alex,性別女,修改ID爲1的學生姓名爲wupeiqi,刪除該數據;
1
2
3
4
5
6
|
insert into
class
(cname) values
(
'一班'
),
(
'二班'
);
insert into student values(
1
,
'alex'
,
'female'
,
'12345'
,
1
);
update student
set
sname
=
'wupeiqi'
where
id
=
1
;
delete
from
student where
id
=
1
;
|
四、查詢student表中,每一個班級的學生數;
1
2
3
4
5
|
insert into student(sname,class_id) values
(
'james'
,
1
),
(
'durant'
,
2
),
(
'curry'
,
3
);
select count(
ID
)
from
student;
|
五、修改credit字段爲unique屬性;
1
|
alter table student modify credit varchar(
32
)
not
null unique;
|
六、請使用命令在你本地數據庫中增長一個用戶,並給該用戶授予建立表的權限;
1
|
grant create on
*
.
*
to
'james'
@
'localhost'
identified by
'123'
;
|
七、請使用pymsql模塊鏈接你本地數據庫,並向student表中插入一條數據;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# _*_ coding: utf-8 _*_
# 七、請使用pymsql模塊鏈接你本地數據庫,並向student表中插入一條數據;
import
pymysql
conn
=
pymysql.connect(
host
=
'127.0.0.1'
,
port
=
3306
,
user
=
'root'
,
password
=
'******'
,
db
=
'test622'
,
charset
=
'utf8'
)
cursor
=
conn.cursor()
sql
=
"insert into student values(13,'park','男','123456',1)"
rows
=
cursor.execute(sql)
conn.commit()
cursor.close()
conn.close()
|
八、請使用mysqldump命令備份student表;
1
|
mysqldump
-
uroot
-
p123 db_bj student >
/
home
/
bj
/
桌面
/
myfile
/
student.sql
|
九、建立一張名爲student_insert_log的表,要求每次插入一條新數據到student表時,都向student_insert_log表中插入一條記錄,記錄student_id, insert_time;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
mysql> desc student;
+
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
| Field |
Type
| Null | Key | Default | Extra |
+
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
|
ID
|
int
(
11
) | NO | PRI | NULL | auto_increment |
| sname | varchar(
16
) | NO | | NULL | |
| gender | enum(
'male'
,
'female'
) | NO | | female | |
| credit | varchar(
32
) | NO | UNI | NULL | |
| class_id |
int
(
11
) | NO | MUL | NULL | |
+
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
create table student_insert_log(
student_id
int
not
null,
insert_time datetime
not
null
);
建立一個觸發器:
delimiter
/
/
create trigger tri_after_insert_student after insert on student
for
each row
begin
insert into student_insert_log values(new.
ID
,now());
end
/
/
delimiter ;
insert into student(sname,credit,class_id) values (
'alice'
,
'123'
,
2
);
insert into student(sname,credit,class_id) values
(
'egon1'
,
'1234'
,
1
),
(
'egon2'
,
'12345'
,
2
);
mysql> select
*
from
student;
+
-
-
-
-
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
|
ID
| sname | gender | credit | class_id |
+
-
-
-
-
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
|
4
| alcie | female |
123456
|
1
|
|
7
| alcie | female |
1234567
|
1
|
|
8
| alice | female |
123
|
2
|
|
9
| egon1 | female |
1234
|
1
|
|
10
| egon2 | female |
12345
|
2
|
+
-
-
-
-
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
mysql> select
*
from
student_insert_log;
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
| student_id | insert_time |
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
|
8
|
2018
-
04
-
24
21
:
29
:
46
|
|
9
|
2018
-
04
-
24
21
:
32
:
05
|
|
10
|
2018
-
04
-
24
21
:
32
:
05
|
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
10
、建立一張名爲student_update_log的表,要求每次更新student表中的記錄時,都向student_update_log表中插入一條記錄,記錄student_id, update_time;
create table student_update_log(
student_id
int
not
null,
update_time datetime
);
建立一個觸發器
delimiter
/
/
create trigger tri_after_update_student after update on student
for
each row
begin
insert into student_update_log values(new.
ID
,now());
end
/
/
delimiter ;
show triggers\G;
update student
set
sname
=
'alex'
where
ID
in
(
9
,
10
);
mysql> select
*
from
student;
+
-
-
-
-
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
|
ID
| sname | gender | credit | class_id |
+
-
-
-
-
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
|
4
| alcie | female |
123456
|
1
|
|
7
| alcie | female |
1234567
|
1
|
|
8
| alice | female |
123
|
2
|
|
9
| alex | female |
1234
|
1
|
|
10
| alex | female |
12345
|
2
|
+
-
-
-
-
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
5
rows
in
set
(
0.00
sec)
mysql> select
*
from
student_update_log;
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
| student_id | update_time |
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
|
9
|
2018
-
04
-
24
21
:
47
:
24
|
|
10
|
2018
-
04
-
24
21
:
47
:
24
|
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
|