Python 异步多线程协程初探

  今天在知乎上看到一篇文章 为什么有人说 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/%E5%85%B3%E4%BA%8E-asyncio-%E7%9A%84%E5%96%83%E5%96%83%E8%87%AA%E8%AF%AD/

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

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

 

你可能感兴趣的:(python3)