python中的进程线程和协程,python中的进程和线程怎么使用
Python 1中的流程。前言2。创建流程的常用方法1。使用多重处理模块2创建流程。使用流程子类3创建流程。使用进程池3创建进程。通过队列实现进程间通信。
一、前言在了解流程之前,我们需要知道多任务的概念。多任务,顾名思义,就是操作系统可以执行多个任务。比如使用Windows或Linux操作系统可以同时看电影、聊天、查看网页。此时操作系统正在执行多个任务,每个任务都是一个进程。我们可以打开Windows的任务管理器,看看系统正在执行的进程,如图所示:
进程是在计算机中运行程序的实体。与程序不同,程序本身只是指令、数据及其组织形式的描述,进程才是程序(指令和数据)真正运行的实例。比如QQ没开的时候,QQ只是一个程序。打开QQ后,系统会为QQ启动一个进程。再打开一个QQ,又一个流程开始了。
二。创建流程的常用方法在Python中,有几个模块可以创建流程。常用的有os.fork()函数、多处理模块和Pool进程池。由于os.fork()函数只适合在Unix/Linux/Mac系统上运行,所以本文重点介绍了两个跨平台模块:多处理模块和池进程池。
1.使用多重处理模块创建进程。多重处理模块提供了一个进程类来表示一个进程对象。语法如下:
进程(组[,目标[,名称[,参数[,kwargs]]])
流程类的参数描述如下:
Group:不使用参数,值始终为None。Target:表示当前进程启动时执行的可调用对象。名称:是当前流程实例的别名。Agrs:表示传递给目标函数的参数元组。Kwargs:表示传递给目标函数的参数字典。例如,用以下代码实例化Process类并执行子进程:
从多重处理导入流程
#执行子流程代码
定义测试(间隔):
打印(“我是子进程”)
#执行主程序
def main():
打印(“主流程开始”)
P=Process (target=test,args=(1,)#实例化Process的进程类
P.start() #启动子程序
打印(“主程序结束”)
if __name__==__main__ :
主()
运行结果如下:
在上面的代码中,首先实例化Process类,然后使用p.start()方法提升进程,开始执行test()函数。除start()外,流程实例p的常用方法还包括以下几种常用方法:
Is_alive():确定流程实例是否仍在执行。Join([timeout]):是否等待流程实例完成执行,或者等待多少秒。Start():启动流程实例(创建子流程)run():如果没有给定target参数,在这个对象上调用start()方法时,将执行对象中的run()方法。Terminate():无论任务是否完成,都立即终止。Process类还具有以下通用属性:
名称:当前流程实例的别名,默认为Proc-N,N是从1开始递增的整数。Pid:当前流程实例的PID值。下面用一个简单的例子来演示process类的方法和属性的使用,创建两个子进程,使用os模块和time模块输出父进程和子进程的ID以及子进程的时间,调用Process类的name和pid属性。代码如下:
# _*_编码:utf-8 _*_
从多重处理导入流程
导入时间
导入操作系统
#将由两个子进程调用的两个方法
def child_1(间隔):
Print(子进程(%s)开始执行,父进程为(%s)% (os.getpid(),os.getppid()))
T_start=time.time() #开始计时。
Time.sleep(interval) #程序将暂停间隔秒
T_end=time.time() #计时结束。
Print(子进程(%s)的执行时间为 %0.2f 秒 % (os.getppid(),t_end-t_start))
def child_2(间隔):
Print(子进程(%s)开始执行,父进程为(%s)% (os.getpid(),os.getppid()))
T_start=time.time() #开始计时。
Time.sleep(interval) #程序将暂停间隔秒
T_end=time.time() #计时结束。
Print(子进程(%s)的执行时间为 %0.2f 秒 % (os.getppid(),t_end-t_start))
if __name__==__main__ :
打印(-)。
Print(父进程PID:%s% os.getpid()) #输出当前程序的PID
P1=进程(target=child _ 1,args=(1,)#实例化进程P1
P2=进程(target=child _ 2,name= mrsoft ,args=(1,)#实例化进程P2
P1.start() #启动进程P1
P2.start() #启动进程P2
#与此同时,父进程正在停止运行,如果p2进程仍在运行,则返回True。
print( P1 . is _ alive=% s % P1 . is _ alive())
print( p2 . is _ alive=% s % p2 . is _ alive())
#输出p1和p2进程的别名和PID
打印( p1.is_alive=%s % p1.name )
打印( p1.pid=%s % p1.pid
打印( p2.is_alive=%s % p2.name )
打印( p2.pid=%s % p2.pid )
打印(-)
P1.join() #等待P1进程结束。
P2.join() #等待P2进程的结束
打印(-)
在上面的代码中,第一次实例化Process类时,name属性会默认赋为“Process-1”,第二次默认赋为“Process-2”。但是,当进程p2被实例化时,name属性被设置为“mrsoft”,所以p2.name的值是“mrsoft”而不是“Process-2”。程序流程图如图所示:
运行结果如图所示:
2.使用Process子类创建流程。对于一些简单的小任务,通常使用Process(target=test)来实现多进程。但是,如果您想要处理复杂任务的流程,您通常会定义一个类,并使其成为流程类。每次实例化这个类,就相当于实例化一个流程对象。让我们通过一个例子来学习如何使用process子类创建多个流程。
使用process子类方法创建两个子流程,分别输出父流程和子流程的PID、子流程的运行状态和运行时间。代码如下:
# _*_编码:utf-8 _*_
从多重处理导入流程
导入时间
导入操作系统
#继承流程类
类别子流程(流程):
#由于Process类本身有一个__init__初始化方法,所以这个子类相当于覆盖了父类的这个方法。
def __init__(self,interval,name= ):
过程。__init__(self) #调用进程父类的初始化方法
Self.interval=interval #接收参数interval
如果名称:
Self.name=name #如果传递了参数name,将为子进程创建name属性,否则将使用默认属性。
#覆盖Process类的run()方法
定义运行(自身):
Print(子进程(%s)开始执行,父进程为(%s)% (os.getpid(),os.getppid()))
t_start=time.time()
时间.睡眠(自我间隔)
t_stop=time.time()
Print(子进程(%s)执行完毕,用了%0.2f秒 % (os.getpid(),t_stop-t_start))
if __name__==__main__ :
打印(-)
Print(父进程PID:% s% os.getpid ()) #输出当前程序的ID
p1=子流程(间隔=1,名称=mrsoft )
p2=子流程(间隔=2)
#对不包含target属性的Process类执行start()方法,这个类中的run()方法就会运行。
#所以p1.run()将在这里执行
P1.start() #启动P1进程。
P2.start() #启动P2进程
#输出p1和p2进程的执行状态,返回True如果它们确实得到执行;否则,将返回False
print( P1 . is _ alive=% s % P1 . is _ alive())
print( p2 . is _ alive=% s % p2 . is _ alive())
#输出p1和p2进程的别名和PID
打印( p1.name=%s % p1.name )
打印( p1.pid=%s % p1.pid
打印( p2.name=%s % p2.name )
打印( p2.pid=%s % p2.pid )
打印(-)
P1.join() #等待P1进程结束。
P2.join() #等待P2进程的结束
打印(-)
在上面的代码中,定义了一个Subprocess子类,它继承了mulitprocess的父类。Process在Subprocess子类中定义了两个方法:__ inti__()初始化方法和run方法。在__ inti__()初始化方法中,调用mulitprocess的父类__ inti__()初始化方法。否则父类初始化方法将被覆盖,进程无法启动。另外,在Subprocess子类中没有定义start()方法,而是在主流程中调用start()方法,然后会自动执行Subprocess类的run()方法。操作结果如下图所示:
3.使用进程池池创建一个进程。在前面,我们使用process类创建了两个流程。如果您想要创建几十或几百个流程,您需要更多的流程类。有没有更好的方法来创建解决这类问题的流程?答案是使用mulitprocessing模块提供的池类,即池进程池。
为了更好地理解进程池,您可以将进程池与池进行比较,如图所示。我们需要完成灌满10个水盆的任务,在这个水池里,最多打开3个水龙头开始放水,也就是我们可以同时执行3个任务,也就是启动3个流程。为了更快完成任务,现在打开三个水龙头,开始放水。当一个盆装满水,也就是流程完成了一个任务,我们就把这个盆里的水倒进桶里,然后继续接水,也就是执行下一个任务。如果三个盆同时装满水,当第9个盆装满水时,系统会随机分配一个盆接水,另外两个盆闲置。
接下来,我们来看看Pool类的常用方法。常见的方法和说明如下:
Apply_async(func[,args[,kwds]]):以非阻塞方式调用func()函数(并执行它,阻塞方式必须等待上一个进程退出后才能执行下一个进程),args是传递给func()函数的参数列表,kwds是传递给func()函数的关键字参数列表。Apply(func[,args[,kwds]]):通过阻塞调用func()函数。Close():关闭池,使其不接受新任务。Terminate():无论任务是否完成,都立即终止。Join():主进程被阻塞,等待子进程退出。它必须在关闭或终止后使用。上面的方法提到apply_async()以非阻塞方式调用函数,而apply()以阻塞方式调用函数。那么什么是堵和不堵呢?如下图所示,三个任务分别在阻塞模式和非阻塞模式下执行。如果使用阻塞方法,则必须等待上一个进程退出,然后才能执行下一个进程。如果使用非阻塞方法,可以并行执行三个进程。
下面的示例演示了如何使用进程池创建多个进程。这里模拟池中放水的场景,定义一个进程池,设置最大进程数为3。然后以非阻塞的方式执行10个任务,检查每个进程执行的任务。具体代码如下:
# _*_编码:utf-8 _*_
从多处理导入池
导入时间
导入操作系统
定义任务(名称):
打印(子进程(%s)执行任务%s . % (os.getpid(),name))
Time.sleep(1) #睡眠1秒钟
if __name__==__main__ :
打印(父进程(%s)。% os.getppid())
P=Pool(3) #定义一个进程池,最大进程数为3。
对于范围(10)内的I:
P.apply_async(task,args=(i,))#以非阻塞方式调用函数task()函数。
打印(等待所有子进程完成.)
p.close()
连接()
打印(所有子进程结束)
运行结果如图所示。从图中可以看出,6588的子进程执行了四项任务,而另外两个子进程分别执行了三项任务。
第三,通过队列实现进程间通信,预测细节。敬请期待下篇,关注鸡,我们一起学习,相约峰会()
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。