python 闯关之路四(下)(并发编程与数据库编程)
并发编程重点:
1
2
3
4
5
6
7
|
并发编程:线程、进程、队列、IO多路模型 操作系统工作原理介绍、线程、进程演化史、特点、区别、互斥锁、信号、 事件、join、GIL、进程间通信、管道、队列。 生产者消息者模型、异步模型、IO多路复用模型、select\poll\epoll 高性 能IO模型源码实例解析、高并发FTP server开发 |
1、请写一个包含10个线程的程序,主线程必须等待每一个子线程执行完成之后才结束执行,每一个子线程执行的时候都需要打印当前线程名、当前活跃线程数量;
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----' )
|
2、请写一个包含10个线程的程序,并给每一个子线程都创建名为"name"的线程私有变量,变量值为“james”;
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 ---' )
|
3、请使用协程写一个消费者生产者模型;
协程知识点:https://www.cnblogs.com/wj-1314/p/9040121.html
协程:单线程下,无法利用多核,可以是一个程序开多个进程,每个进程开启多个线程,每隔线程开启协程;
协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程。
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() |
4、写一个程序,包含十个线程,子线程必须等待主线程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 ()
|
5、写一个程序,包含十个线程,同时只能有五个子线程并行执行;
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()
|
6、写一个程序 ,包含一个名为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()
|
7、写一个程序,利用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 ( '主' )
|
8、写一个程序,利用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())
|
9、使用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' ))
|
10、使用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()
|
11、请使用asyncio实现一个socket服务器端程序;
12、写一个程序,使用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 旧字段名 新字段名 新数据类型 [完整性约束条件…];
|
1、创建一个表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 )
); |
2、在上面的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;
|
3、向该表新增一条数据,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 ;
|
4、查询student表中,每个班级的学生数;
1
2
3
4
5
|
insert into student(sname,class_id) values ( 'james' , 1 ),
( 'durant' , 2 ),
( 'curry' , 3 );
select count( ID ) from student;
|
5、修改credit字段为unique属性;
1
|
alter table student modify credit varchar( 32 ) not null unique;
|
6、请使用命令在你本地数据库中增加一个用户,并给该用户授予创建表的权限;
1
|
grant create on * . * to 'james' @ 'localhost' identified by '123' ;
|
7、请使用pymsql模块连接你本地数据库,并向student表中插入一条数据;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# _*_ coding: utf-8 _*_ # 7、请使用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() |
8、请使用mysqldump命令备份student表;
1
|
mysqldump - uroot - p123 db_bj student > / home / bj / 桌面 / myfile / student.sql
|
9、创建一张名为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 |
+ - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - +
|