PythonPython学习

Python并发编程——协程

2021-05-16  本文已影响0人  xiaogp

摘要:Python协程gevent

协程基本概念

协程,又称微线程,纤程。英文名Coroutine,是Python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元。 它自带CPU上下文。这样只要在合适的时机, 可以把一个协程切换到另一个协程。,切换的次数以及什么时候再切换由开发者自己确定

(1)协程和线程差异

在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存的数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住,简单而言协程的特点是

(2)协程对比进程线程

Python中协程的实现

主要整理Python中使用gevent实现协程的代码实现,gevent是一个基于协程的Python网络库,在遇到IO阻塞时,程序会自动进行切换,可以让开发者用同步的方式写异步IO代码

(1)gevent的基本使用

gevent通过gevent.spawn创建协程任务,传入执行函数,可以给执行函数传入多个参数,使用joinall启动任务且主进程等待协程执行完毕退出

import time
import datetime

import gevent


def my_func(sid, sid2):
    time.sleep(3)
    print("sid:{}, sid2:{}, time:{}".format(sid, sid2, datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S")))


t1 = gevent.spawn(my_func, sid="a", sid2="b")  # t1 = gevent.spawn(my_func, "a", "b")
t2 = gevent.spawn(my_func, sid="a", sid2="b")
gevent.joinall([t1, t2])

输出如下,没有达到并行效果,还是顺序执行,需要增加gevent.monkey补丁

sid:a, sid2:b, time:2021-05-16 20:10:51
sid:a, sid2:b, time:2021-05-16 20:10:54

加入补丁如下

import time
import datetime

import gevent
from gevent import monkey
monkey.patch_all()


def my_func(sid, sid2):
    time.sleep(3)
    print("sid:{}, sid2:{}, time:{}".format(sid, sid2, datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S")))


t1 = gevent.spawn(my_func, sid="a", sid2="b")
t2 = gevent.spawn(my_func, sid="a", sid2="b")
gevent.joinall([t1, t2])

输出如下

sid:a, sid2:b, time:2021-05-16 20:14:19
sid:a, sid2:b, time:2021-05-16 20:14:19

(2)协程池的使用

协程池相对要好用些,可以自定义一个协程池指定个数,把待执行的列表丢进去,即可执行

import time
import datetime

import gevent
from gevent import monkey
from gevent.pool import Pool
monkey.patch_all()


def my_func(sid, sid2):
    time.sleep(3)
    print("sid:{}, sid2:{}, time:{}".format(sid, sid2, datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S")))


if __name__ == '__main__':
    pool = Pool(4)
    jobs = [["a", "b"], ["b", "c"], ["c", "d"], ["d", "e"]]
    for job in jobs:
        pool.apply_async(my_func, job)
    pool.join()

如果函数有输出值,则可以使用map获得协程池的执行结果,gevent的协程池不支持map传入多个执行函数的参数,可以在执行函数中解包如下

import time
import datetime

import gevent
from gevent import monkey
from gevent.pool import Pool
monkey.patch_all()


def my_func(sid: tuple):
    sid1 = sid[0]
    sid2 = sid[1]
    time.sleep(3)
    print("sid:{}, sid2:{}, time:{}".format(sid1, sid2, datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S")))
    return str(sid1) + str(sid2)


if __name__ == '__main__':
    pool = Pool(4)
    jobs = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e")]
    res = pool.map(my_func, jobs)
    pool.join()
    print(res)

输出如下

sid:a, sid2:b, time:2021-05-16 22:09:40
sid:b, sid2:c, time:2021-05-16 22:09:40
sid:c, sid2:d, time:2021-05-16 22:09:40
sid:d, sid2:e, time:2021-05-16 22:09:40
['ab', 'bc', 'cd', 'de']
上一篇下一篇

猜你喜欢

热点阅读