python 内置的线程池、进程池及其并发服务器的实现

python 内置的线程池、进程池及其并发服务器的实现

内置线程池

 1 from multiprocessing.pool import ThreadPool  # 导入线程池
 2 import time
 3 w_start = time.time()
 4 def worker():
 5     time.sleep(3)
 6     print('55555')
 7 pool = ThreadPool(2)  # 参数是线程池的数量,默认为1
 8 pool.apply_async(worker)
 9 pool.apply_async(worker)
10 pool.apply_async(worker)
11 pool.close()  # 关闭线程池 不再提交任务
12 pool.join()  # 等待线程池里面的任务执行完毕
13 print(time.time() - w_start)
14 ############### 运行结果:##########
15 55555
16 55555
17 55555
18 6.055918216705322

这里运行了6秒是因为线程池的数量为2,最多开两个线程,且这里是time.sleep(3),延迟操作,所以会两个线程

同时执行,实际上是遇到sleep阻塞之后就执行线程2了,所以两个线程执行了大概3秒!如果涉及计算密集型,

多线程是没用的,因为python默认一次智能执行一个!join之后再使用apply_async()方法就会报错,因为这个

时候线程池已经关了,而且这里没有start()方法可以调用再次开启...

内置进程池:

 1 from multiprocessing import Pool  # 进程池
 2 import time
 3 w_start = time.time()
 4 def worker(kill=0):
 5     time.sleep(3)
 6     print('子进程正在执行{}'.format(kill))
 7 pool = Pool(4)  # 参数是进程池的数量,不写默认是1个进程
 8 for i in range(5):
 9     pool.apply_async(worker)
10 pool.map_async(worker, [1, 2, 3])  # 把任务给进程池,加async之后,就不会等待运行结束
11 pool.close()  # 关闭线程池 不再提交任务
12 pool.join()  # 等待线程池里面的任务执行完毕
13 print(time.time() - w_start)
14 print('任务执行结束')
15 ###########运行结果:###########
16 子进程正在执行0
17 子进程正在执行0
18 子进程正在执行0
19 子进程正在执行0
20 子进程正在执行0
21 子进程正在执行1
22 子进程正在执行2
23 子进程正在执行3
24 6.215780258178711
25 任务执行结束

  注意到这里的方法都有两种如:map()------->map_async()

前者会阻塞,加async就不会阻塞。apply()和apply_async()是同样的。

用线程池(或者进程池)实现并发服务器:

 1 from multiprocessing.pool import ThreadPool
 2 import socket
 3 
 4 server = socket.socket()
 5 server.bind(('', 12345))
 6 server.listen(6)
 7 print('--------等待客户端连接------')
 8 def worker(conn):
 9     while True:
10         recv_data = conn.recv(1024)
11         if recv_data:
12             print(recv_data)
13             conn.send(recv_data)
14         else:
15             conn.close()
16             break
17 if __name__ == '__main__':
18     pool = ThreadPool(3)
19     while True:
20         conn, address = server.accept()
21         pool.apply_async(worker, args=(conn,))

  由于进程池和线程池API接口设置的都一样,所以用进程池可以将ThreadPool改成Pool,导包的时候也要修改。

其他代码都差不多。ThreadPool()默认开启1个线程(线程池只有一个),这是我电脑的结果,但是老师运行调试的是

cpu的核数!

posted @ 2018-04-03 10:00  巴蜀秀才  阅读(2487)  评论(0编辑  收藏  举报