python实现进程的三种方式及其区别

在python中有三种方式用于实现进程
多进程中, 每个进程中所有数据( 包括全局变量) 都各有拥有⼀份, 互不影响

1.fork()方法

ret = os.fork()
if ret == 0:
#子进程
else:
#父进程

这是python中实现进程最底层的方法,其他两种从根本上也是利用fork()方法来实现的,下面是fork()方法的原理示意图


getpid()、getppid()方法
import os
rpid = os.fork()
if rpid<0:
print("fork调⽤失败。 ")
elif rpid == 0:
print("我是⼦进程( %s) , 我的⽗进程是(%s) "%(os.getpid(),os.getppid()))
x+=1
else:
print("我是⽗进程( %s) , 我的⼦进程是( %s) "%(os.getpid(),rpid)) print("⽗⼦进程都可以执⾏这⾥的代码")

运行结果:

我是⽗进程( 19360) , 我的⼦进程是( 19361)
⽗⼦进程都可以执⾏这⾥的代码
我是⼦进程( 19361) , 我的⽗进程是( 19360)
⽗⼦进程都可以执⾏这⾥的代码
注意:
(1)其中os.fork()的返回值ret在第一行执行后,会开辟另外一个子进程,然后父进程跟子进程同时从此句往下执行,对于子进程来说,ret值是0,对于父进程来说ret值是一个大于0的值,这个值实际上就是新开子进程的pid.
(2)此种开辟进程的方式不会发生堵塞,也就是父进程结束并不会影响子进程的继续执行。实际上是根据操作系统的调度算法来实现的,父子进程相互不影响。
多进程修改全局变量
#coding=utf-8
import os
import time num = 0 # 注意, fork函数, 只在Unix/Linux/Mac上运⾏, windows不可以
pid = os.fork() if pid == 0:
num+=1
print('哈哈1---num=%d'%num)
else:
time.sleep(1)
num+=1
print('哈哈2---num=%d'%num)

运行结果

哈哈1---num=1
哈哈2---num=1
#多进程不共享全局变量
多次fork()问题
结论:多次fork()会有多个进程生成,生成规则同上。
2,Process方法
python是跨平台的,所以自然肯定会为我们提供实现多进程的库,毕竟在win里面用不了fork()。此方法需要导入对应模块
from multiprocessing import Process
p1=Process(target=xxxx)
p1.start()
这个方法常用场景是使用少量进程做主动服务,如qq客户端,等这样的可以开多个。
还可以继承Process模块并实现run方法来调用,此时xxxx方法等价于run方法执行的内容,在重写过run方法后,在执行子类实例对象的start方法时,会自动调用实现的run方法,这个跟java里面也是类似的。
注意,此种方法子进程不结束,父进程也会堵塞,也就是等子进程都结束后,父进程才会结束,通常应用于进程间的同步。
代码实现演示
#coding=utf-8
from multiprocessing import Process
import os # ⼦进程要执⾏的代码
def run_proc(name):
print('⼦进程运⾏中, name= %s ,pid=%d...' % (name, os.getpid())) if __name__=='__main__':
print('⽗进程 %d.' % os.getpid())
p = Process(target=run_proc, args=('test',))
print('⼦进程将要执⾏')
p.start()
p.join()
print('⼦进程已结束')
运行结果
⽗进程 4857.
⼦进程将要执⾏
⼦进程运⾏中, name= test ,pid=4858...
⼦进程已结束
Process类常⽤⽅法:

is_alive(): 判断进程实例是否还在执⾏;

join([timeout]): 是否等待进程实例执⾏结束, 或等待多少秒;

start(): 启动进程实例( 创建⼦进程) ;

run(): 如果没有给定target参数, 对这个对象调⽤start()⽅法时, 就将执⾏对象中的run()⽅法;

terminate(): 不管任务是否完成, ⽴即终⽌;
3,利用进程池Pool
当需要创建的⼦进程数量不多时, 可以直接利⽤multiprocessing中的Process动态成⽣多个进程, 但如果是上百甚⾄上千个⽬标, ⼿动的去创建进程的⼯作量巨⼤, 此时就可以⽤到multiprocessing模块提供的Pool⽅法。此方法也需导入对应模块
from multiprocessing import Pool
pool=Pool(3)
pool.apply_async(xxxx)
xxxx表示要在进程中运行的代码块或方法、函数
此方法可以用来做服务器端的响应,往往主进程比较少,而Pool()中的参数值,也就是进程池的大小,真正的任务都在子进程中执行。
使用示例
from multiprocessing import Pool
import os,time,random def worker(msg):
t_start = time.time()
print("%s开始执⾏,进程号为%d"%(msg,os.getpid()))
#random.random()随机⽣成0~1之间的浮点数
time.sleep(random.random()*2)
t_stop = time.time()
print(msg,"执⾏完毕, 耗时%0.2f"%(t_stop-t_start)) po=Pool(3) #定义⼀个进程池, 最⼤进程数3
for i in range(0,10):
#Pool.apply_async(要调⽤的⽬标,(传递给⽬标的参数元祖,))
#每次循环将会⽤空闲出来的⼦进程去调⽤⽬标
po.apply_async(worker,(i,))
print("----start----")
po.close() #关闭进程池, 关闭后po不再接收新的请求
po.join() #等待po中所有⼦进程执⾏完成, 必须放在close语句之后
print("-----end-----")

运行结果

----start----
----start----
0开始执⾏,进程号为5025
----start----
1开始执⾏,进程号为5026
----start----
----start----
----start----
----start----
----start----
----start----
----start----
2开始执⾏,进程号为5027
0 执⾏完毕, 耗时0.58
3开始执⾏,进程号为5025
1 执⾏完毕, 耗时0.70
4开始执⾏,进程号为5026
2 执⾏完毕, 耗时1.36
5开始执⾏,进程号为5027
3 执⾏完毕, 耗时1.03
6开始执⾏,进程号为5025
4 执⾏完毕, 耗时1.12
7开始执⾏,进程号为5026
5 执⾏完毕, 耗时1.25
8开始执⾏,进程号为5027
7 执⾏完毕, 耗时1.28
9开始执⾏,进程号为5026
6 执⾏完毕, 耗时1.91
8 执⾏完毕, 耗时1.23
9 执⾏完毕, 耗时1.38
-----end-----
上面使用的是非堵塞方法,如果使用aply(),则是堵塞方法
from multiprocessing import Pool
import os,time,random def worker(msg):
t_start = time.time()
print("%s开始执⾏,进程号为%d"%(msg,os.getpid()))
#random.random()随机⽣成0~1之间的浮点数
time.sleep(random.random()*2)
t_stop = time.time()
print(msg,"执⾏完毕, 耗时%0.2f"%(t_stop-t_start)) po=Pool(3) #定义⼀个进程池, 最⼤进程数3 for i in range(0,10):
po.apply(worker,(i,)) print("----start----")
po.close() #关闭进程池, 关闭后po不再接收新的请求
po.join() #等待po中所有⼦进程执⾏完成, 必须放在close语句之后
print("-----end-----")

运行结果

0开始执⾏,进程号为5280
0 执⾏完毕, 耗时0.91
1开始执⾏,进程号为5281
1 执⾏完毕, 耗时1.59
2开始执⾏,进程号为5282
2 执⾏完毕, 耗时1.25
3开始执⾏,进程号为5280
3 执⾏完毕, 耗时0.53
4开始执⾏,进程号为5281
4 执⾏完毕, 耗时1.49
5开始执⾏,进程号为5282
5 执⾏完毕, 耗时0.18
6开始执⾏,进程号为5280
6 执⾏完毕, 耗时1.51
7开始执⾏,进程号为5281
7 执⾏完毕, 耗时0.88
8开始执⾏,进程号为5282
8 执⾏完毕, 耗时1.08
9开始执⾏,进程号为5280
9 执⾏完毕, 耗时0.12
----start----
-----end-----
multiprocessing.Pool常⽤函数解析:

apply_async(func[, args[, kwds]])
: 使⽤⾮阻塞⽅式调⽤func( 并⾏执⾏, 堵塞⽅式必须等待上⼀个进程退出才能执⾏下⼀个进程) , args为传递给func的参数列表, kwds为传递给func的关键字参数列表;
apply(func[, args[, kwds]]): 使⽤阻塞⽅式调⽤funcclose(): 关闭Pool, 使其不再接受新的任务;
terminate(): 不管任务是否完成, ⽴即终⽌;
join(): 主进程阻塞, 等待⼦进程的退出, 必须在close或terminate之后使⽤;

python核心高级学习总结3-------python实现进程的三种方式及其区别的更多相关文章

  1. python实现进程的三种方式及其区别

    在python中有三种方式用于实现进程 多进程中, 每个进程中所有数据( 包括全局变量) 都各有拥有⼀份, 互不影响 1.fork()方法 ret = os.fork() if ret == 0: # ...

  2. python核心高级学习总结5--------python实现线程

    在代码实现上,线程的实现与进程的实现很类似,创建对象的格式都差不多,然后执行的时候都是用到start()方法,与进程的区别是进程是资源分配和调度的基本单位,而线程是CPU调度和分派的基本单位.其中多线 ...

  3. 判断python对象是否可调用的三种方式及其区别

    查找资料,基本上判断python对象是否为可调用的函数,有三种方法 使用内置的callable函数 callable(func) 用于检查对象是否可调用,返回True也可能调用失败,但是返回False ...

  4. python核心高级学习总结7---------正则表达式

    正则表达式在爬虫项目中应用很广泛,主要方面就是在字符串处理方面,经常会涉及到字符串格式的校验,用起来经常要查看文档才能完成,所以抽了个时间将正则的内容复习了一下. Start re---导入re模块使 ...

  5. python核心高级学习总结8------动态性、__slots__、生成器、迭代器、装饰、闭包

    python的动态性 什么是动态性呢,简单地来说就是可以在运行时可以改变其结构,如:新的函数.对象.代码都可以被引进或者修改,除了Python外,还有Ruby.PHP.javascript等也是动态语 ...

  6. python核心高级学习总结6------面向对象进阶之元类

    元类引入 在多数语言中,类就是一组用来描述如何生成对象的代码段,在python中同样如此,但是在python中把类也称为类对象,是的,你没听错,在这里你只要使用class关键字定义了类,其解释器在执行 ...

  7. python核心高级学习总结1---------*args和**kwargs

    *args 和 ** kwargs 的用法 首先,这两者在用法上都是用来补充python中对不定参数的接受. 比如下面的列子 def wrappedfunc(*args, **kwargs): pri ...

  8. python核心高级学习总结4-------python实现进程通信

    Queue的使用 Queue在数据结构中也接触过,在操作系统里面叫消息队列. 使用示例 # coding=utf-8 from multiprocessing import Queue q = Que ...

  9. python核心高级学习总结2----------pdb的调试

    PDB调试 def getAverage(a,b): result =a+b print("result=%d"%result) return result a=100 b=200 ...

随机推荐

  1. 不能再被问住了!ReentrantLock 源码、画图一起看一看!

    前言 在阅读完 JUC 包下的 AQS 源码之后,其中有很多疑问,最大的疑问就是 state 究竟是什么含义?并且 AQS 主要定义了队列的出入,但是获取资源.释放资源都是交给子类实现的,那子类是怎么 ...

  2. 【Kata Daily 190908】How Much?

    原题: I always thought that my old friend John was rather richer than he looked, but I never knew exac ...

  3. input 与 button 的问题 (空隙/不等高/对不齐)及 解决办法

    1. input 与 button 为什么有空隙? - 要明白为什么,需要了解一下几点基础知识(耐心看完,你会发现竟如此简单)     1. input 与 button 都属于行级块元素,都具有文本 ...

  4. 【SpringCloud】08.客户端负载均衡器:Ribbon

    客户端负载均衡器:Ribbon Ribbon实现软负载均衡核心: 服务发现 :依据服务的名字,把该服务下所有的实例都找出来 服务选择规则:依据规则策略,如果从多个实例中,选出有效的服务 服务监听:检测 ...

  5. 9、Django之模型层第四篇:进阶操作

    一 QuerySet对象 1.1可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFSET 子句. Entry.objects.all()[:5] # ...

  6. python爬虫00什么是爬虫

    用一个自动化的程序把网站背后的程序爬取下来. 在互联网上许许多多的网站,他们都是托管在服务器上的,这些服务器24小时运行着,刻刻 等待着别人的请求.所以,爬虫首先会模拟请求,就好像你在浏览器输入网址, ...

  7. 预训练模型——开创NLP新纪元

    预训练模型--开创NLP新纪元 论文地址 BERT相关论文列表 清华整理-预训练语言模型 awesome-bert-nlp BERT Lang Street huggingface models 论文 ...

  8. 硬盘LBA 和CHS的关系(转)

    磁头数 × 磁道(柱面)数 × 每道扇区数 × 每扇区字节数 l         磁头(head)数:每个盘片一般有上下两面,分别对应1个磁头,共2个磁头:l         磁道(track)数:磁 ...

  9. C语言环境总结

    1.虚拟内存下C语言环境 2.main函数调用 3.栈调用 每次函数调用,在栈中分配一个栈帧,寄存器通过持有该栈帧的基地址,并上下偏移,访问形参和本地变量, C语言形参为一个字大小,所以通常传指针,这 ...

  10. 【java从入门到精通】day10-Java流程控制2-switch多选择结构

    1.switch多选择结构 switch case语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支. switch语句中的变量类型可以是: byte.short.int或者char 从j ...