Python 并发编程从入门到进阶

开发 后端
Python有真正的多线程吗?我本来以为是没有的。因为CPython解释器本身就不是线程安全的,因此有全局解释器锁(GIL),一次只允许使用一个线程执行Python字节码。

[[439938]]

Python多线程

Python有真正的多线程吗?我本来以为是没有的。因为CPython解释器本身就不是线程安全的,因此有全局解释器锁(GIL),一次只允许使用一个线程执行Python字节码。换句话说,Python即便是有多线程,也会受GIL限制,按顺序执行。所以我就以为Python是没有多线程的,也就是一个Python进程不能同时使用多个CPU核心。然而,Python标准库中所有执行阻塞型I/O操作的函数,在等待操作系统返回结果时,都会释放GIL,允许其他线程运行。这就意味着Python线程在I/O密集型应用中还是可以发挥作用的,比如一个Python线程等待网络响应时,阻塞型I/O函数会释放GIL,再运行一个线程。再比如time.sleep()函数也会释放GIL。

Python多进程

但是对于CPU密集型应用来说,要想利用所有可用的CPU核心,就得使用多进程,规避GIL。

多线程与多进程对比

什么时候用多线程?什么时候用多进程?

I/O密集型应用使用多线程,CPU密集型应用使用多进程。

什么是I/O密集型应用?什么是CPU密集型应用?

简单来说,I/O密集一般涉及到网络、磁盘IO。而CPU密集指的是计算比较多。

创建多线程可以使用concurrent.futures,创建多进程可以使用multiprocessing。

多线程与协程对比

多线程存在着切换开销,同时为了避免写变量冲突,在控制共享资源时需要加锁,因此编写程序会比较复杂比较困难。而协程是通过单线程实现的并发,既能自由切换,也不需要锁机制,执行效率要高很多。

多线程和协程有个共同点是只对I/O密集型应用有效,因为GIL限制。如果想处理CPU密集型应用,那么可以结合多进程一起使用,以提高CPU使用率。

asyncio包

asyncio包比较多用来实现Python协程并发,原书在这一章节引用了很多示例,穿插了很多代码,导致我看起来有点乱,不是很清楚到底该怎么使用这个包。所以我看了一下官方文档:

https://docs.python.org/3/library/asyncio.html

从Python3.5开始引入了async和await,替代了@asyncio.coroutine和yield from语法,语义更简洁更明确了。并且从Python3.7开始引入了asyncio.run(),替代了这一串代码:

  1. loop = asyncio.get_event_loop() 
  2. try: 
  3.     loop.run_until_complete(main()) 
  4. finally: 
  5.     loop.close() 

创建task的语法也发生了变化,可以用asyncio.create_task:

  1. async def coro(): 
  2.     ... 
  3.  
  4. In Python 3.7+ 
  5. task = asyncio.create_task(coro()) 
  6. ... 
  7.  
  8. # This works in all Python versions but is less readable 
  9. task = asyncio.ensure_future(coro()) 
  10. ... 

对于多个并行task可以用asyncio.gather,替代asyncio.wait:

  1. task_list = [] 
  2.     for i in range(5): 
  3.         task = asyncio.create_task(async_func(i)) 
  4.         task_list.append(task) 
  5.  
  6. done, pending = await asyncio.wait(task_list, timeout=None) 
  7. for done_task in done: 
  8.         print((f"[{current_time()}] 得到执行结果 {done_task.result()}")) 
  1. task_list = [] 
  2.     for i in range(5): 
  3.         task = asyncio.create_task(func(i)) 
  4.         task_list.append(task) 
  5. results = await asyncio.gather(*task_list) 
  6. for result in results: 
  7.         print((f"[{current_time()}] 得到执行结果 {result}")) 

所以对于第三方包的学习,最好是看看最新的官方文档,说不定已经进行了很多优化。

 

最后,完结,撒花。

 

责任编辑:武晓燕 来源: dongfanger
相关推荐

2023-12-26 08:40:06

分类算法数据分析Python

2022-03-23 08:45:20

系统性能CPU

2023-02-10 09:40:36

Go语言并发

2022-07-15 16:31:49

Postman测试

2024-02-26 08:52:20

Python传递函数参数参数传递类型

2023-09-22 22:43:26

eval()Python

2024-04-11 14:00:28

2018-07-04 09:30:07

Python书籍程序员

2011-06-07 10:33:11

Android Activity

2024-06-07 08:51:50

OpenPyXLPythonExcel文件

2020-07-07 10:50:19

Python丄则表达文本

2017-06-26 09:15:39

SQL数据库基础

2024-01-11 09:35:12

单元测试Python编程软件开发

2023-05-09 08:34:51

PythonWith语句

2012-02-29 00:49:06

Linux学习

2013-06-06 13:42:48

OSPF入门配置

2023-12-14 15:31:43

函数式编程python编程

2013-12-18 13:30:19

Linux运维Linux学习Linux入门

2022-06-10 08:17:52

HashMap链表红黑树

2022-10-20 08:02:29

ELFRTOSSymbol
点赞
收藏

51CTO技术栈公众号