并发编程重点:
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
|
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
|