Python 异步多线程协程初探

    xiaoxiao2022-07-02  125

      今天在知乎上看到一篇文章 为什么有人说 Python 多线程是鸡肋? 中Python中的多线程是单核多线程,是伪多线程!为什么会这么说?

      由于Python 中 GIL。正是这个锁能保证同时只有一个线程在运行。罪魁祸首::。但如果去掉GIL的 Python 在单线程条件下执行效率将近慢了2倍。~~如果一定要通过多线程利用多核,那只能通过C扩展来实现,不过这样就失去了Python简单易用的特点。

      当然,对于 IO 密集型的程序,Python目前对 多线程性能还是有很大地改善的。 Python 3.4引入的 asyncio 模块来实现“协程”。

    协程其实也是一种线程,其开销比threading小。而且它是Python3.4引入的新标准库 asyncio。asyncio的编程模型是一个消息循环。需要从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,实现了异步IO。这里的EventLoop有点像线程池。

      这就使得很多 IO 操作有了更好的方式去解决,虽然Python没有真正意义上的多线程,但采用 Event Loop 来处理耗时的 IO 操作,效果非常好。

      下面简单聊聊多线程协程之间的协作:

      EventLoop 总是与 thread 共存,它只是负责接收事件,余下的由 thread 来解决,保证并发。

      下面举一个测试例子:

    def task(): for i in range(5): time.sleep(1) print("task--"+str(i)) def run_loop_inside_thread(loop): loop.run_forever() new_loop = asyncio.new_event_loop() asyncio.set_event_loop(new_loop) loop = asyncio.get_event_loop() threading.Thread(target=run_loop_inside_thread, args=(loop,)).start() loop.call_soon_threadsafe(task) return "finish"

    上面的例子,主要是在主线程中创建一个new_loop,然后在另外的子线程中开启一个无限事件循环。主线程通过call_soon_threadsafe新注册协程对象。这样就能在子线程中进行事件循环的并发操作,同时主线程又不会被block。

    如果想传参的话,则可如下面所写:(传参6到more_work方法中)

    .call_soon_threadsafe(more_work, 6)

    其中:

    event_loop 是 asyncio 的起点,是执行所有事件的起点

    通过 loop.run_forever() + loop.call_* 实现对事件的调度

      如果不加

    new_loop = asyncio.new_event_loop() asyncio.set_event_loop(new_loop)

    则会报错:RuntimeError: There is no current event loop in thread 'Thread-1'。为什么会这样?根据asyncio的文档介绍,asyncio的事件循环不是线程安全的,一个event loop只能在一个线程内调度和执行任务,并且同一时间只有一个任务在运行。

      处于非主线程时,还需要调用set_event_loop方法指定一个event loop对象,这样get_event_loop才会获取到被标记的event loop对象

      但如果你只是运行 一个只有主线程的demo 的话,会发现 asyncio.get_event_loop()来获取 event_loop,是没问题的。

      上面的例子中的call_soon_threadsafe是asynico在多线程情况下专门针对线程安全的调用的解决方案。一般如果event loop在主线程中运行的话,子线程是不能使用它来调度任务。

     

      值得注意点是:在非阻塞的情况下,多线程是同步的代表,而协程是异步的代表。二者都可以开启多个线程。在多线程中,多个线程会竞争谁先运行,一个等待结束也不会去通知主程序,这样没有章法的随机运行会造成一些资源浪费。而在协程中,多个线程(称为微线程)的调用和等待都是通过明确代码组织的。协程就像目标明确地执行一个又一个任务,而多线程则会在竞争过程中性能有所降低。

    ~~

     

    参考:

    https://www.zhihu.com/question/23474039

    https://juejin.im/post/5aeba17e6fb9a07a9e4d1318

    http://yshblog.com/blog/124

    https://www.cnblogs.com/shenh/p/9090586.html

    https://juejin.im/post/5aa7338e6fb9a028c6755f72

    https://binglau7.github.io/2018/01/30/关于-asyncio-的喃喃自语/

    https://juejin.im/entry/5b3d99565188251b134e5355

    https://www.jianshu.com/p/b5e347b3a17c

     

    最新回复(0)