Python(进程池与协程)

1.进程池与线程池:
为什么要用“池”:池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务
池子内什么时候装进程:并发的任务属于计算密集型
池子内什么时候装线程:并发的任务属于IO密集型

1、进程池
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import time,os,random

def task(x):
    print('%s 接客' %os.getpid())
    time.sleep(random.randint(2,5))
    return x**2

if __name__ == '__main__':
    p=ProcessPoolExecutor() # 默认开启的进程数是cpu的核数

    # alex,武佩奇,杨里,吴晨芋,张三

    for i in range(20):
        p.submit(task,i)

2、线程池
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import time,os,random

def task(x):
    print('%s 接客' %x)
    time.sleep(random.randint(2,5))
    return x**2

if __name__ == '__main__':
    p=ThreadPoolExecutor(4) # 默认开启的线程数是cpu的核数*5

    # alex,武佩奇,杨里,吴晨芋,张三

    for i in range(20):
        p.submit(task,i)
2.同步、异步、阻塞、非阻塞
1、阻塞与非阻塞指的是程序的两种运行状态
阻塞:遇到IO就发生阻塞,程序一旦遇到阻塞操作就会停在原地,并且立刻释放CPU资源
非阻塞(就绪态或运行态):没有遇到IO操作,或者通过某种手段让程序即便是遇到IO操作也不会停在原地,执行其他操作,力求尽可能多的占有CPU

2、同步与异步指的是提交任务的两种方式:
同步调用:提交完任务后,就在原地等待,直到任务运行完毕后,拿到任务的返回值,才继续执行下一行代码
异步调用:提交完任务后,不在原地等待,直接执行下一行代码。等全部执行完毕后取出结果

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import time,os,random

def task(x):
    print('%s 接客' %x)
    time.sleep(random.randint(1,3))
    return x**2

if __name__ == '__main__':
    # 异步调用
    p=ThreadPoolExecutor(4) # 默认开启的线程数是cpu的核数*5

    # alex,武佩奇,杨里,吴晨芋,张三

    obj_l=[]
    for i in range(10):
        obj=p.submit(task,i)
        obj_l.append(obj)

    # p.close()
    # p.join()
    p.shutdown(wait=True) (等同于p.close()(不允许向池中放新任务) + p.join())

    print(obj_l[3].result())
    print(''# 同步调用
    p=ThreadPoolExecutor(4) # 默认开启的线程数是cpu的核数*5

    # alex,武佩奇,杨里,吴晨芋,张三

    for i in range(10):
        res=p.submit(task,i).result()

print('')
2.协程
1、单线程下实现并发:协程 (为了提高效率;但不是说所有协程都会提升效率)
   并发指的多个任务看起来是同时运行的;并发实现的本质:切换+保存状态
   有效的协程在一定程度‘骗过’了CPU;通过自己内部协调,一遇到IO就切到自己的其他程序中,使得CPU以为这个程序一直在运行,从而使其更有可能处于就绪态或运行态,以更多的占用CPU。
2、实现并发的三种手段:
a)单线程下的并发;由程序自己控制,相对速度快
b)多线程下的并发;由操作系统控制,相对速度较慢
c)多进程下的并发;由操作系统控制,相对速度慢

3、基于yield保存状态,实现两个任务直接来回切换,即并发的效果 (但yield不会遇到阻塞自动切程序)
   PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.

import time
def consumer():
    '''任务1:接收数据,处理数据'''
    while True:
        x=yield

def producer():
    '''任务2:生产数据'''
    g=consumer()
    next(g)
    for i in range(10000000):
        g.send(i)

start=time.time()
producer() #1.0202116966247559
stop=time.time()
print(stop-start)

# 纯计算的任务并发执行
import time
def task1():
    res=1
    for i in range(1000000):
        res+=i
        yield
        time.sleep(10000)  #yield不会自动跳过阻塞
        print('task1')

def task2():
    g=task1()
    res=1
    for i in range(1000000):
        res*=i
        next(g)
        print('task2')

start=time.time()
task2()
stop=time.time()
print(stop-start)

一、单线程下实现遇到IO切换
1、用greenlet(封装yield,遇到IO不自动切)
from greenlet import greenlet
import time

def eat(name):
    print('%s eat 1' %name)
    time.sleep(30)
    g2.switch('alex')  #只在第一次切换时传值
    print('%s eat 2' %name)
    g2.switch()
def play(name):
    print('%s play 1' %name)
    g1.switch()
    print('%s play 2' %name)

g1=greenlet(eat)
g2=greenlet(play)
g1.switch('egon')

2、用gevent模块(封装greenlet,不处理的话,遇到自己的IO才主动切)
import gevent

def eat(name):
    print('%s eat 1' %name)
    gevent.sleep(5)  #换成time.sleep(5),不会自动切
    print('%s eat 2' %name)
def play(name):
    print('%s play 1' %name)
    gevent.sleep(3)
    print('%s play 2' %name)

g1=gevent.spawn(eat,'egon')
g2=gevent.spawn(play,'alex')

# gevent.sleep(100)
# g1.join()
# g2.join()
gevent.joinall([g1,g2])

3、用gevent模块(封装greenlet,处理的话,遇到其他IO也主动切)
from gevent import monkey;monkey.patch_all()
from threading import current_thread
import gevent
import time

def eat():
    print('%s eat 1' %current_thread().name)
    time.sleep(5)
    print('%s eat 2' %current_thread().name)
def play():
    print('%s play 1' %current_thread().name)
    time.sleep(3)
    print('%s play 2' %current_thread().name)

g1=gevent.spawn(eat)
g2=gevent.spawn(play)

# gevent.sleep(100)
# g1.join()
# g2.join()
print(current_thread().name)
gevent.joinall([g1,g2])

 

转载于:https://www.cnblogs.com/zhaijihai/p/9629986.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值