< Python全景系列-5 > 解锁Python并发编程:多线程和多进程的神秘面纱揭晓

欢迎来到我们的系列博客《Python全景系列》!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语法。无论你是编程新手,还是有一定基础的开发者,这个系列都将提供你需要的知识和技能。

 

这是本系列的第五篇,我们将深入探讨Python中的并发编程,特别关注多线程和多进程的应用。我们将先从基本概念开始,然后通过详细举例探讨每一种机制,最后分享一些实战经验以及一种优雅的编程技巧。

 

第一部分:多线程介绍

线程是操作系统中最小的执行单元。在单个程序或进程内,可以并发运行多个线程,共享进程的资源,如内存和文件描述符。

1.1 Python中的多线程

Python支持多线程编程,并提供了`threading`模块作为支持。这个模块提供了`Thread`类,我们可以通过创建其实例并向其传递函数来创建新线程。当然,你也可以通过继承`Thread`类并重写`run()`方法来创建自定义线程。下面是一个多线程编程的例子:

import threading

def print_numbers():
    for i in range(10):
        print(i)

def print_letters():
    for letter in 'abcdefghij':
        print(letter)

# 创建线程
t1 = threading.Thread(target=print_numbers)
t2 = threading.Thread(target=print_letters)

# 启动线程
t1.start()
t2.start()

# 等待线程结束
t1.join()
t2.join()

 

在上面的例子中,我们定义了两个函数:一个打印数字,另一个打印字母。然后我们创建了两个线程,每个线程的目标是执行这些函数。`start()`方法用于启动线程,而`join()`方法用于等待线程完成。

 

1.2 多线程的实际应用

尽管Python的多线程因为全局解释器锁(GIL)的存在,并不能实现真正的并行,但是它们在I/O密集型任务中仍然很有用。GIL是CPython解释器的一个互斥锁,保证在任何时刻只有一个线程在执行。这意味着在CPU密集型任务中,多线程可能不是最佳选择,因为它们无法充分利用多核CPU。

然而,在I/O密集型任务中,多线程能够提高程序性能。例如,如果一个程序需要从多个源下载文件,那么使用多线程可以使得当一个线程等待网络响应时,其他线程可以继续下载其他文件。这样,程序可以在同一时间从多个源下载文件,大大提高了效率。

 

第二部分:多进程介绍

进程是操作系统中独立的执行实体,每个进程都有自己的内存空间、文件描述符等资源。与线程不同,进程之间的资源

并不共享,每个进程都有自己独立的资源。

 

2.1 Python中的多进程

 

Python通过`multiprocessing`模块提供了多进程支持。类似于多线程,我们可以通过创建`Process`类的实例并向其传递函数来创建新进程。我们也可以通过继承`Process`类并重写`run()`方法来创建自定义进程。

以下是一个简单的多进程编程的例子:

import multiprocessing

def print_numbers():
    for i in range(10):
        print(i)

def print_letters():
    for letter in 'abcdefghij':
        print(letter)

# 创建进程
p1 = multiprocessing.Process(target=print_numbers)
p2 = multiprocessing.Process(target=print_letters)

# 启动进程
p1.start()
p2.start()

# 等待进程结束
p1.join()
p2.join()

这个例子和前面的多线程例子类似,不同的是这里我们创建的是两个进程,而不是线程。

 

2.2 多进程的实际应用

多进程可以实现真正的并行,使得Python程序可以利用多核CPU。因此,对于CPU密集型任务,多进程通常比多线程更有优势。另一方面,多进程的开销比多线程大,而且进程间的通信和同步也比线程间的更为复杂。因此,对于I/O密集型任务,或者需要频繁通信的任务,多线程可能会是更好的选择。

第三部分:优化并发编程的技巧

在Python中,`concurrent.futures`模块为多线程和多进程编程提供了高级接口,可以让我们更加简洁地编写代码。

这个模块提供了`ThreadPoolExecutor`和`ProcessPoolExecutor`两个类,它们分别用于创建线程池和进程池。这两个类都实现了相同的接口,你可以使用`submit()`方法提交任务,然后使用`as_completed()`函数等待任务完成。

下面是一个使用`concurrent.futures`模块的示例:

 
import concurrent.futures

def print_numbers():
    for i in range(10):
        print(i)

def print_letters():
    for letter in 'abcdefghij':
        print(letter)

# 使用线程池
with concurrent.futures.ThreadPoolExecutor() as executor:
    future1 = executor.submit(print_numbers)
    future2 = executor.submit(print_letters)
    for future in concurrent.futures.as_completed([future1, future2]):
        pass

# 使用进程池
with concurrent.futures.ProcessPoolExecutor() as executor:
    future1 = executor.submit(print_numbers)
    future2 = executor.submit(print_letters)
    for future in concurrent.futures.as_completed([future1, future2]):
        pass

在上面的例子中,我们创建了线程池和进程池,然后向它们提交任务。可以看到,使用`concurrent.futures`模块,我们的代码更加简洁,易读性和可维护性也有所提高。

总结

Python的多线程和多进程都是非常强大的工具,可以帮助我们编写出更高效的程序。然而,它们也各有优缺点,需要我们根据具体的任务和需求来选择。同时,Python还提供了`concurrent.futures`模块,可以使我们的并发编程变得更加简单和高效。

我们希望本文能帮助你更好地理解和使用Python的多线程和多进程。如果你有任何疑问或者建议,欢迎在评论区留言。

【第一时间获得Python全视角更新信息,请关注本人微信公众号: Python全视角

 

***** 【第一时间获得Python全视角更新信息,请关注本人微信公众号: Python全视角】 TeahLead_KrisChang,10+年的互联网和人工智能从业经验,10年+技术团队和业务团队管理经验,同济软件工程本科,复旦工程管理硕士,阿里云认证云服务资深架构师,上亿营收AI产品业务负责人。丰富的传统软件工程、互联网软件工程、人工智能软件工程经验和心得,擅长将复杂结构业务软件服务落地、底层技术架构、工程管理、多元角色业务团队建设、英文无障碍沟通。主流全栈技术均有涉猎,擅长Python/Go和Linux/Windows,致力于设计和实现最适合业务发展的软件工程最佳实践。 *****
本文转载于网络 如有侵权请联系删除

相关文章

  • MATLAB-数据类型

    默认情况下,MATLAB®存储所有数值变量为双精度浮点值。其他数据类型存储文本,整数或单精度值或单个变量中相关数据的组合。MATLAB不需要任何类型声明或维度语句。当MATLAB遇到新的变量名称时,它将创建变量并分配适当的内存空间。如果变量已经存在,则MATLAB将使用新内容替换原始内容,并在必要时分配新的存储空间。例如:a=136;复制上述语句创建一个名为a的1x1矩阵,并将值136存储在其中。MATLAB数据类型示例数据类型转换数据类型确定示例 使用以下代码创建脚本文件:a=3 isinteger(a) isfloat(a) isvector(a) isscalar(a) isnumeric(a) a=23.54 isinteger(a) isfloat(a) isvector(a) isscalar(a) isnumeric(a) a=[123] isinteger(a) isfloat(a) isvector(a) isscalar(a) a='Hello' isinteger(a) isfloat(a) isvector(a) isscalar(a)

  • 测试平台接入HttpRunner V4(二)使用config实现用例之间的参数传递

    使用config实现例参之间的数传递这几天在群里看到有些人的疑问,就是在各用例间的参数无法传递,比如登录状态、响应结果等。基于下面2种情况,虽然我觉得要保持用例的独立性,但真正要做到用例相对独立是比较困难的。同时我也有第1种情况的需求,所以就开始整理,下面代码会以header为例进行实现,参数导出也可以同样实现 1.用例1设置的token,在用例2上无法使用,导致每个用例都要单独做登录的操作,导致操作繁琐 2.用例1接口的返回结果,无法在用例2上使用,如果把多个用例放在同一个文件,会导致需要引用用例1的用例都需要加上,后期维护是个比较大的问题如何接入下面代码在测试平台接入HttpRunnerV4(一)基本功能接入基础上修改使用config进行传参,那么就需要使用应用传参,这样才操作后才可以在后续的用例中引用typeTestCaseJsonstruct{ JsonStringstring IDuint DebugTalkFilePathstring Config*TConfig//增加config引用传参 Namestring }复制func(testCaseJson*Test

  • Android APP专项测试工具iTest

    Part.1最近公司发布了一款android应用,也是由我负责测试,因为这款应用的功能比较简单,所以在保证功能的基础上,我专门做了一些app稳定性的测试。在测试期间,发现了一款超好用的测试工具iTest,简单介绍给大家。Part.2这个款iTest工具是科大讯飞一个团队开发的,我们可以在以下网址 http://itest.iflytek.com/进行下载。如图:下载完成,我们可以通过adb命令安装到对于对于的手机上(这个需要电脑搭建adb环境),如下: Part.31安装完成后,我们就直接可以在手机上进行操作了,就行和我平常用微信一样简单。打开iTest工具后,我们需要注册一个账号进行登录 2登录之后,我们需要进行对iTest工具进行授权,如下: 点击确定,让其获得悬浮窗权限,然后再点击我已授权,然后下一步,再次允许申请权限,需要在pc端允许所提示的adb命令 允许以下adb命令: adb命令运行完成后,点击确定,就会进入工具使用的界面,如下:Part.4性能指标监控监控CPU/PSS/网络等性能指标: 先添加需要监控的APP,如下,我以爱奇艺App为例子 添加完成app后,点击启动监

  • linux学习笔记02用户篇

    Linux是一套免费使用和自由传播的类UNIX操作系统,其内核由林纳斯·本纳第克特·托瓦兹于1991年第一次释出,它主要受到Minix和Unix思想的启发,是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统。 用户组su可以切换到用户user,执行时需要输入目标用户的密码,sudo可以以特权级别运行cmd命令,需要当前用户属于sudo组,且需要输入当前用户的密码。 su-命令也是切换用户,同时环境变量也会跟着改变成目标用户的环境变量现在我们新建一个叫lilei的用户:$sudoadduserlilei复制这个命令不但可以添加用户到系统,同时也会默认为新用户创建home目录:现在你已经创建好一个用户,并且你可以使用你创建的用户登录了,使用如下命令切换登录用户:$su-llilei复制输入刚刚设置的lilei的密码,然后输入如下命令并查看输出:whoami复制退出当前用户跟退出终端一样可以使用exit命令或者使用快捷键Ctrl+d。在Linux里面每个用户都有一个归属(用户组),用户组简单地理解就是一组用户的集合,它们共享一些资源和权限,同时拥有私有资源,就跟家

  • mybatis映射器之select

    select元素是最常用的,也是功能最强大的元素。他的功能就是执行select查询,可以动态设定入参,还可以把resultset的数据转为指定的javabean。select元素的配置元素说明备注id他和mapper的命名空间组合起来必须是唯一的,提供给mybatis调用如果命名空间和id组合起来不唯一,mybatis将会抛异常paramterType入参类型可以是类的全命名,也可以使类的别名(必须是在mybatis中定义好的)可以选择javabean,map等复杂类型传递参数给sqlparameterMap废弃废弃resultType返回结果类型,可以是类的全路径,也可以是别名,也可以是八大基础类型不能和resultMap一起使用resultMap返回结果的复杂映射,可以定义复杂映射规则需要在配置文件中设置映射规则flushCache在调用sql后,是否清空之前查询的本地缓存和二级缓存取值为布尔类型,true/falseuseCache启动二级缓存,是否缓存此次结果取值为布尔类型,true/falsetimeout设置超时参数,等待超时将抛出异常,单位为秒默认值是jdbc驱动或连接池

  • java开发_org.apache.commons.lang.StringUtils工具类源码

    在之前写了一篇关于""和null区别的文章。下面是文章的地址:http://www.cnblogs.com/hongten/archive/2012/11/08/java_null.html下面看看org.apache.commons.lang.StringUtils工具类源码1/* 2*LicensedtotheApacheSoftwareFoundation(ASF)underoneormore 3*contributorlicenseagreements.SeetheNOTICEfiledistributedwith 4*thisworkforadditionalinformationregardingcopyrightownership. 5*TheASFlicensesthisfiletoYouundertheApacheLicense,Version2.0 6*(the"License");youmaynotusethisfileexceptincompliancewith 7*theLicense.Youmayobtainacopy

  • 如何高效学Python?

    如果你一直想学Python,但是不知道如何入手,那就别犹豫了。这篇文章就是为你写的。(由于微信公众号外部链接的限制,文中的部分链接可能无法正确打开。如有需要,请点击文末的“阅读原文”按钮,访问可以正常显示外链的版本。)疑问随着数据科学概念的普及,Python这门并不算新的语言火得一塌糊涂。因为写了几篇用Python做数据分析的文章,经常有读者和学生在留言区问我,想学习Python,该如何入手?我经常需要根据他们的不同情况,提出对应的建议。这样针对性虽强,但效率不高。这个问题,我还是写出来,让更多的人一同看到吧。有几位出版社的编辑,给我发私信,鼓励我赶紧写一本Python教材出来。我暂时还没有写Python基础教程的计划。因为在我看来,现有的学习资源已经足够好了。有现成的资源和路径,为什么许多人依然在为学Python犯愁呢?因为学习有个效率问题。Python语法清晰明快,简单易学。这是Python如此普及的重要原因。但是,选择合适的Python学习方式,需要跟你自身的特性相结合。人群划分的标准是什么?不是你是否计算机相关专业,也不是你是否已经工作,而是一个重要的指标——你的自律能力。你可

  • LintCode 线段树系列问题(线段树的构造,线段树的构造||,线段树的查询,线段树的查询II,线段树的修改)线段树的构造线段树的构造 II线段树的查询线段树查询 II线段树的修改

    线段树(又称区间树),是一种高级数据结构,他可以支持这样的一些操作: 查找给定的点包含在了哪些区间内查找给定的区间包含了哪些点线段树的构造题目线段树是一棵二叉树,他的每个节点包含了两个额外的属性start和end用于表示该节点所代表的区间。start和end都是整数,并按照如下的方式赋值:根节点的start和end由build方法所给出。对于节点A的左儿子,有start=A.left,end=(A.left+A.right)/2。对于节点A的右儿子,有start=(A.left+A.right)/2+1,end=A.right。如果start等于end,那么该节点是叶子节点,不再有左右儿子。实现一个build方法,接受start和end作为参数,然后构造一个代表区间[start,end]的线段树,返回这棵线段树的根。代码/** *DefinitionofSegmentTreeNode: *publicclassSegmentTreeNode{ *publicintstart,end; *publicSegmentTreeNodeleft,right; *publicSegmentTre

  • 干货|「大数据」和「深度学习」有什么区别?

    简单来说:1)深度学习(DeepLearning)只是机器学习(MachineLearning)的一种类别,一个子领域。机器学习>深度学习 2)大数据(BigData)不是具体的方法,甚至不算具体的研究学科,而只是对某一类问题,或需处理的数据的描述具体来说:1)机器学习(MachineLearning)是一个大的方向,里面包括了很多种approach,比如deeplearning,GMM,SVM,HMM,dictionarylearning,knn,Adaboosting...不同的方法会使用不同的模型,不同的假设,不同的解法。这些模型可以是线性,也可以是非线性的。他们可能是基于统计的,也可能是基于稀疏的....不过他们的共同点是:都是data-driven的模型,都是学习一种更加abstract的方式来表达特定的数据,假设和模型都对特定数据广泛适用。好处是,这种学习出来的表达方式可以帮助我们更好的理解和分析数据,挖掘数据隐藏的结构和关系。MachineLearning的任务也可以不同,可以是预测(prediction),分类(classification),聚类(cluster

  • 如何实现一个SQL解析器

    ​作者:vivo互联网搜索团队-DengJie一、背景随着技术的不断的发展,在大数据领域出现了越来越多的技术框架。而为了降低大数据的学习成本和难度,越来越多的大数据技术和应用开始支持SQL进行数据查询。SQL作为一个学习成本很低的语言,支持SQL进行数据查询可以降低用户使用大数据的门槛,让更多的用户能够使用大数据。本篇文章主要介绍如何实现一个SQL解析器来应用的业务当中,同时结合具体的案例来介绍SQL解析器的实践过程。二、为什么需要SQL解析器?在设计项目系统架构时,我们通常会做一些技术调研。我们会去考虑为什么需要SQL解析器?怎么判断选择的SQL解析器可以满足当前的技术要求?2.1传统的SQL查询传统的SQL查询,依赖完整的数据库协议。比如数据存储在MySQL、Oracle等关系型数据库中,有标准的SQL语法。我们可以通过不同的SQL语句来实现业务需求,如下图所示:但是,在处理海量数据的时候,关系型数据库是难以满足实际的业务需求的,我们需要借助大数据生态圈的技术组件来解决实际的业务需求。2.2实际应用场景在使用大数据生态圈的技术组件时,有些技术组件是自带SQL的,比如Hive、Spa

  • Javascript基础巩固系列——标准库Array对象

    全手打原创,转载请标明出处:https://www.cnblogs.com/dreamsqin/p/13720869.html,多谢,=。=~(如果对你有帮助的话请帮我点个赞啦) 重新学习JavaScript是因为当年转前端有点儿赶鸭子上架的意味,我一直在反思我的知识点总是很零散,不能在脑海中形成一个完整的体系,所以这次想通过再次学习将知识点都串联起来,结合日常开发的项目,达到温故而知新的效果。与此同时,总结一下我认为很重要但又被我遗漏的知识点~ 静态方法 Array.isArray() 返回布尔值表示参数是否为数组,弥补了typeof运算符的不足(对于数组来说直接返回了object类型)。 vararr=[1,2,3]; typeofarr//"object" Array.isArray(arr)//true 复制 实例方法 valueOf()和toString() 数组的valueOf方法返回数组本身,toString方法返回数组的字符串形式(因为数组对toString做了自定义)。 vararr=[1,2,3]; arr.valueOf()//[1,2,3] arr.toS

  • 替换空格

    题目描述 请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为WeAreHappy.则经过替换之后的字符串为We%20Are%20Happy。   1publicclassSolution{ 2publicStringreplaceSpace(StringBufferstr){ 3returnstr.toString().replace("","%20"); 4} 5}复制  

  • Memory

    Memory   fromCats Midnight Notasoundfromthepavement Hasthemoonlosthermemory Sheissmilingalone Inthelamplight Thewitheredleavescollectatmyfeet Andthewindbeginstomoan   Memory Allaloneinthemoonlight Icansmileattheolddays Iwasbeautifulthen Iremember ThetimeIknewwhathappinesswas Letthememoryliveagain   Everystreetlamp Seemstobeat Afatalisticwarning Someonemutters Andastreetlampgutters Andsoonitwillbemorning   Daylight Imustwaitforthesunrise Imustthinkofanewlife AndImustn'tgivein Whent

  • 模板—字符串—KMP(单模式串,单文本串)

    模板—字符串—KMP(单模式串,单文本串) Code: #include<cstdio> #include<cstring> #include<algorithm> usingnamespacestd; #defineN1000010 intf[N],n,ans,len1,len2;charstr1[N],str2[N]; intmain() { scanf("%s%s",str2+1,str1+1),len1=strlen(str1+1),len2=strlen(str2+1); for(inti=1,j=0;i<len1;f[++i]=j) { while(j&&str1[i+1]!=str1[j+1])j=f[j]; if(str1[i+1]==str1[j+1])j++; } for(inti=1,j=0;i<=len2;i++) { while(j&&str2[i]!=str1[j+1])j=f[j]; if(str2[i]==str1[j+1])j++; if(

  • Android分辨率适配心得

      关于Android分辨率适配,这个是Android开发很头疼的一个问题,也需要花费相当一部分开发时间处理的一个问题,往往一个界面怎么适配就得想半天,特别是新手,也经常有人问我是怎么适配分辨率的,我也不能几句话说清楚,自己也在研究中。   其实,我觉得分辨率适配,不只是研发单方面的事情,与产品、UI设计师也有很大关联。首先产品必须了解一点Android布局以及分辨率适配的知识,设计的界面布局可以尽量简洁一点,效果图界面显示效果尽量稀疏一点,考虑到各个尺寸的手机每个界面的显示情况。其次,UI设计师设计时,也最好先定义一些级别的尺寸,例如一个应用的所有文字大小只有6个级别,所有界面的设计都尽量在这6个级别中选取,不要每个界面文字都不同,这样终端如果在配置文件里配置文字大小,就只需要6个配置了,另外,按钮背景等的切图,能不使用颜色渐变就不使用颜色渐变,这样终端可以使用.9.png的图片,既减小apk的尺寸,又节约应用内存。   分辨率适配必须了解的知识:   SupportingMultipleScreens:http://wiki.eoeandroid.com/Supporting_Mu

  • SQL 统计 字段 竖向转横向 (行转列)显示

    公司某应用总体监控界面的一个场景显示各个状态作业的数目,由于有个别作业链中作业数有上万了,整个作业链界面刷新效率要求需要在一条sql中解决 1建表语句 1createtablewb( 2app_idint, 3job_link_idvarchar(255), 4job_idvarchar(255), 5up_job_idvarchar(255), 6proc_statusvarchar(32) 7)复制 2初始化数据 1insertinto`wb`(`app_id`,`job_link_id`,`job_id`,`up_job_id`,`proc_status`)values 2(1,'job_link2','job_id1','up_job_id2','N'), 3(1,'job_link2','job_idc','up_job_id2','N'), 4(1,'job_link2','job_ide','up_job_id2','N'), 5(1,'job_link2','job_id1','up_job_id1','N'), 6(1,'job_link2','job_id1'

  • 小白也能看懂的插件化DroidPlugin原理(三)-- 如何拦截startActivity方法

      前言:在前两篇文章中分别介绍了动态代理、反射机制和Hook机制,如果对这些还不太了解的童鞋建议先去参考一下前两篇文章。经过了前面两篇文章的铺垫,终于可以玩点真刀实弹的了,本篇将会通过Hook掉startActivity方法的一个小例子来介绍如何找出合适的Hook切入点。 开始之前我们需要知道的一点就是,其实在Android里面启动一个Activity可以通过两种方式实现,一种是我们常用的调用Activity.startActivity 方法,一种是调用Context.startActivity方法,两种方法相比之下,第一种启动Activity的方式更为简单,所以先以第一种为例。   本系列文章的代码已经上传至github,下载地址:https://github.com/lgliuwei/DroidPluginStudy 本篇文章对应的代码在 com.liuwei.proxy_hook.hook.activityhook包内,下载下来对照代码看文章效果会更好! 一、Hook掉Activity的startActivity的方法   在HookAc

  • neutron 解决客户端超时的问题

    环境中删除或者开通虚机失败报错关于neutron的client网关超时504的解决方案 报错如图     neutron通讯不稳定导致的,解决方案为在haproxy里配置neutron的server和client的代理时间       配置如上图的timeout时间可以为1200s左右  重启haproxy解决    

  • Java基础(011):Java程序的初始化顺序

      Java程序初始化顺序,结论如下: 初始化顺序:父类静态变量、父类静态代码块、子类静态变量、子类静态代码块、父类非静态变量、父类非静态代码块、父类构造函数、子类非静态变量、子类非静态代码块、子类构造函数 总结起来就是3点:先静态后普通,先超类后子类,而且都得按照声明顺序,具体说明如下: 静态的包括静态变量、静态代码块,超类的先按声明顺序执行完再是子类的 静态变量和静态代码块只会在对应的Class类加载时初始化一次 普通的包括实例变量+代码块+构造函数,也是超类的先按声明顺序执行后才是子类的 相当于在构造器里面先调用父类构造器super(),然后再执行实例变量初始化、代码块初始化,最后才执行构造器中的代码。   其实也很好理解:静态部分在类的加载时执行,而父类先于子类实例化。 参考: [1]12.1.3.InitializeTest:ExecuteInitializers https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.1.3 [2]12.4.Initial

  • 图片破碎插件【Destructible 2D】

    B站视频教学 https://www.bilibili.com/video/BV1Qt411i7Ce?p=2&spm_id_from=pageDriver

  • javascript事件对象

    <style>div{width:100px;height:100px;background-color:red;}</style>   <script> vardiv=document.querySelector(‘div’); div.addEventListener(‘click’,function(event){  //event就是一个事件对象,写到我们的侦听函数的括号里面,当做一个形参来看                      //事件对象只有了事件才会存在,是系统自动给我们创建的,不需要我们传参数   console.log(event);          //事件对象就是一系列跟事件方法相关数据的集合                      //事件对象我们可以自己命名eventevte                      //事件对象也有兼容性问题ie678  e=e||window.event; })       </script&

相关推荐

推荐阅读