进程池,线程池以及协程

进程池和线程池

进程池线程池:硬件有极限,为了减轻硬件压力,就有了池的概念
#进程池例子
from concurrent.futures import ProcessPoolExecutor
import os, time

pool = ProcessPoolExecutor(5)  # 实例化一个进程池对象,里面可以存放5个进程
lis=[]
def task(n):
    time.sleep(1)
    print(n,'is running',os.getpid())
    return n ** 2


def call_back(mes):
    print(mes.result(), os.getpid())

if __name__ == '__main__':
    for i in range(10):
        future = pool.submit(task, i)
        future.add_done_callback(call_back)  #回调,运行结束自动执行call_back函数
	pool.shutdown() #关闭进程池,等待所有进程结束
	print('main')        
	 
#线程池例子      
from concurrent.futures import ThreadPoolExecutor
from threading import current_thread
import time

pool=ThreadPoolExecutor(5) #实例化一个线程池对象,里面可以存放5个线程

def task(n):
	print(n,current_thread().name,' is running')
    time.sleep(1)
    return n**3

def call_back(n):
	print(n.result(),current_thread().getName())
    
for i in range(10):
    future=pool.submit(task)
    future.add_done_callback(call_back)
pool.shutdown()
print('main')

协程

协程:单线程下实现并发(能够在多个任务直接切换并保存状态),这里注意区分操作系统的切换+保存状态是针对多个线程而言,而我们现在是想在单个线程下实现操作系统切换+保存状态的功能

协程在操作系统中并不存在,它是程序员想象出来的概念,操作系统只有线程与进程。在遇到IO时候切换可以提高效率,但是没有遇到IO仍然切换,这样就额外增加了切换时间,降低了效率。

将单个线程的效率提升到最高,再配合多进程与多线程,实现高并发

方法一:yield
	yield虽然可以配合.next(),来回切换,实现并发,但是yield并不能帮我们捕捉到IO行为,而且相比函数的直接调用,增加了切换时间

方法二:gevent模块
一个spawn就是帮助管理任务的对象
   
注意:gevent模块并不能识别它本身以外(如gevent.sleep(sec))的所有IO行为,但是内部封装了一个模块(monkey),可以帮助我们识别所有的IO行为(所以要提前导入)

from gevent import monkey;monkey.patch_all()	#检测所有的IO行为
from gevent import spawn,joinall #joinall列表中放入多个对象,实现join的效果
import time

def part1(s):
    print('%s 正在啃鸡腿'%s)
    time.sleep(3)
    print('%s 正在喝牛奶'%s)
    
def part2(s):
    print('%s 正在吃冰激凌'%s)
    time.sleep(5)
    print('%s 吃饱了'%s)
    
start=time.time()   
p1=spawn(part1,'wo')
p2=spawn(part2,'wo')
joinall([p1,p2])#就等于p1.join() 和 p2.join()
print('买单,用餐时间',time.time()-start)

协程实现服务端与客户端通信

链接和通信都是IO密集型操作,我们只需要在这两者之间来回切换其实就能实现并发的效果

服务端检测链接和通信,客户端同时链接服务端

#例子
服务端
from gevent import monkey;monkey.patch_all()
from gevent import spawn
import socket
def server(ip,port,backlog=5)
    server=socket.socket()
    server.bind((ip,port))
    server.listen(backlog)
    while True:
        conn,addr=server.accept()
        print(addr)
        spawn(communicate,conn)

def communicate(conn):
    while True:
        try:
            data=conn.recv(1024)
            print(data.decode('utf-8'))
            conn.send(b'message had get')
		except ConnectionResetError:
            break
	conn.close()

p=spawn(server,'127.0.0.1',8080)
p.join()

客户端
from threading import Thread,current_thread
import socket
def task(n):
    client=socket.socket()
    client.connect(('127.0.0.1',8080))
    while True:
        client.send('%s is running from %s'%(n,current_thread().name).encode('utf-8'))
        data=client.recv(1024)
        print(data)

for i in range(500):
    p=Thread(target=task,args=(i,))

IO模型

- 阻塞IO

- 非阻塞IO(服务端通信针对accept用s.setblocking(False)加异常捕获,cpu占用率过高)

- IO多路复用

  在只检测一个套接字的情况下,他的效率连阻塞IO都比不上。因为select这个中间人增加了环节。

  但是在检测多个套接字的情况下,就能省去wait for data过程

- 异步IO
posted @ 2019-05-09 16:49  Mr-Bear  阅读(138)  评论(0编辑  收藏  举报