Python 多线程进程高级指南(二)

简介:

本文是如何《优雅地实现Python通用多线程/进程并行模块》的后续。因为我发现,自认为懂了一点多线程开发的皮毛,写了那么个multi_helper的玩意儿,后来才发现我靠原来就是一坨屎。自己辛苦开发的并行库,在Python的原生类库中就有了优雅地多的实现。并且还有更优雅的asyncio库!这简直让人累觉不爱。

首先,并行和并发是不同的。100个进程可以在1个CPU上并发地执行,但却能在4个CPU上并行地执行。这就能看出两者的不同。

在实际编程中,有大量的计算或IO是一下子无法结束的。那么如何充分利用各种资源呢?有两个流派:

  • 多进程,多线程(并行)
  • 协程 (并发)

本文实在不能算完整,但汇集了笔者觉得很精髓的不少内容,因此可以认为是一篇综述性文章。

多线程和多进程

先说前者,定义本身是常识就不多说。初级程序员为了让程序变快,于是就狂开线程,不论是IO操作还是计算,能开100个就绝不开50个。线程回收一律不管,这程序只能是玩具。

不过,众所周知Python有GIL(全局解释器锁),任何时候都只有一个线程在工作。那多线程加速还玩个屁啊?!龟叔站出来了,他说:

  • Python在IO操作时,会自动释放GIL,因此IO密集型程序的多线程是有意义的
  • 即使不能多线程,还能多进程,这才是核武器。而Python有非常好用的multiprocessing库解决进程间协同问题。

然而,这些耗时任务,如果不需要知道结果,那还好说(很多程序员直接就把结果写到不同的文件里去,从而避免此问题,太low了)。可是每次都写文件再读出来这太麻烦了。如何收集计算结果呢?

笔者那个工具的做法,是将结果保存到一个队列中,从外部对其进行消费。但Python官方库早就有类似的实现了,多线程和多进程版本分别叫ThreadPoolExecutorProcessPoolExecutor。至于怎么用,出门问度娘。老司机在文章里贴代码太没有逼格了。

好,你度娘上完了。我们会发现他们都在concurrent.futures库里。这个表述很有意思。这是未来才能知道结果的任务,因此叫future。 在《Python高手之路》的第14章里,这样的概念叫期物。你如果你要获取某个任务的result,就必须等待该任务完成。也可以创建任务的数组,然后批量去执行它。类似的还有C#的async关键字以及task的result属性。

让我觉得比较神奇的是,Python的python-parallelize库,就能隐含地将for循环转换为并行for循环,代码更加简洁。这才是多进程的终极神器。写法如下:

import os
from parallelize import parallelize
    
for i in parallelize(range(100)):
    print(os.getpid(), i)

你要做的,仅仅是在迭代器外面套上套子,其他并行的操作就都由它执行完了。你猜这个库的核心代码有多少行?30行不到!它用os.fork创建出很多子进程,之后将不同的任务分配到这些进程上。而代码编写和串行程序几乎没有区别。

对多数人来说,高阶函数本来就比较反人类。这样写下来反而会清爽很多。值得学习!这部分写完了,我们进入协程的神秘世界。

asyncio 和 yield from

协程(coroutine)是比线程更轻量级的概念。大家会好奇协程的本质,因为当年学C语言时可是完全没这个东西啊。协程说白了就是语法糖。编译器会把协程的一坨东西整合到大的状态机里,类似于一堆switch-case和while的代码里,从而实现无缝调度。但对代码编写者来说,同一语义的依然能在同一个代码位置,从而更好理解。

yield是Python中的关键字。我们熟悉的是它的迭代生成器用法。更高阶的则是协程。例如:

a=yield b

如果你认为a=b,那就大错特错了。a是外部send函数的返回值。至于更详细的信息,可参考

http://www.jianshu.com/p/d09778f4e055

到了Python3, 更丧心病狂的yield from横空出世。最浅显的理解,是下面的代码:

def merge():
    yield from 'ABC'
    yield from '123'

于是在merge执行循环时,A,B,C,1,2,3会依次返回。那么肯定会有人纳闷,为何不直接itertools.chain呢?因为yield from有更复杂的功能,即能够让外部的generator对内部做消息传递。yield from 就像一个套子,无缝地将生成器merge了起来。

更详细的信息,可参考

http://blog.theerrorlog.com/yield-from-in-python-3.html

它有什么用呢?asyncio.

如果你喜欢C#的await和async关键字,则一定会对它的表现印象深刻。异步函数再也不用像js那样做疯狂的回调,顿时代码清晰了很多。这些也是编译器大人的功劳。

详细的可参考:

http://blog.jobbole.com/63897/

看得其实还是晕乎乎的,尽管我自认为对yield和协程有了相对充分的了解却依然如此。

结语

大神说,不要重复造轮子。你会发现之前想做的所有事情,都有远比你想的优雅的多的实现

不过问题在于,用了协程,yield from, asyncio,别人就看不懂我写的代码了,并且不得不升级到py3,可维护性顿时下降很多。因为我发现,就我身边会python的人来说,熟悉且能灵活使用以上那些语义的人不到百分之一。

有任何问题,随时交流。


作者:热情的沙漠
出处:http://www.cnblogs.com/buptzym/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。


 本文转自FerventDesert博客园博客,原文链接:http://www.cnblogs.com/buptzym/p/6950172.html,如需转载请自行联系原作者

目录
相关文章
|
1月前
|
调度 开发者 Python
深入浅出操作系统:进程与线程的奥秘
在数字世界的底层,操作系统扮演着不可或缺的角色。它如同一位高效的管家,协调和控制着计算机硬件与软件资源。本文将拨开迷雾,深入探索操作系统中两个核心概念——进程与线程。我们将从它们的诞生谈起,逐步剖析它们的本质、区别以及如何影响我们日常使用的应用程序性能。通过简单的比喻,我们将理解这些看似抽象的概念,并学会如何在编程实践中高效利用进程与线程。准备好跟随我一起,揭开操作系统的神秘面纱,让我们的代码运行得更加流畅吧!
|
1月前
|
消息中间件 Unix Linux
【C语言】进程和线程详解
在现代操作系统中,进程和线程是实现并发执行的两种主要方式。理解它们的区别和各自的应用场景对于编写高效的并发程序至关重要。
62 6
|
1月前
|
调度 开发者
深入理解:进程与线程的本质差异
在操作系统和计算机编程领域,进程和线程是两个核心概念。它们在程序执行和资源管理中扮演着至关重要的角色。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
63 5
|
1月前
|
算法 调度 开发者
深入理解操作系统:进程与线程的管理
在数字世界的复杂编织中,操作系统如同一位精明的指挥家,协调着每一个音符的奏响。本篇文章将带领读者穿越操作系统的幕后,探索进程与线程管理的奥秘。从进程的诞生到线程的舞蹈,我们将一起见证这场微观世界的华丽变奏。通过深入浅出的解释和生动的比喻,本文旨在揭示操作系统如何高效地处理多任务,确保系统的稳定性和效率。让我们一起跟随代码的步伐,走进操作系统的内心世界。
|
1月前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
60 4
|
2月前
|
数据采集 存储 数据处理
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
|
2月前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
2月前
|
监控 JavaScript 前端开发
python中的线程和进程(一文带你了解)
欢迎来到瑞雨溪的博客,这里是一位热爱JavaScript和Vue的大一学生分享技术心得的地方。如果你从我的文章中有所收获,欢迎关注我,我将持续更新更多优质内容,你的支持是我前进的动力!🎉🎉🎉
30 0
|
2月前
|
数据采集 Java Python
爬取小说资源的Python实践:从单线程到多线程的效率飞跃
本文介绍了一种使用Python从笔趣阁网站爬取小说内容的方法,并通过引入多线程技术大幅提高了下载效率。文章首先概述了环境准备,包括所需安装的库,然后详细描述了爬虫程序的设计与实现过程,包括发送HTTP请求、解析HTML文档、提取章节链接及多线程下载等步骤。最后,强调了性能优化的重要性,并提醒读者遵守相关法律法规。
74 0
|
6月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
下一篇
开通oss服务