python进程-进程的执行顺序是计算机的调度算法决定的
python进程
-
创建子进程-fork
import os import time ret = os.fork() #os.fork 会创建一个子进程 把父进程赋值给ret 父进程大于0 然后把子进程赋值给ret等于0 if ret == 0: while True:#子进程执行 print("----1----") time.sleep(1) else: while True:#父进程执行 print("----2----") time.sleep(1) #父进程创建了子进程 但不一定父进程就会先执行 跟局操作系统的调度算法 决定 # 运行结果 ----2---- ----1---- ----1---- ----2---- ----2---- ----1---- ----2---- ----1---- ----1---- ----2---- 死循环
-
fork的返回值-getpid-getppid
import os ret = os.fork() #从这句话开始 下面的代码父子进程都执行 print(ret) if ret>0: print("----父进程--%d--"%os.getpid()) #父进程中fork的返回值,就是刚刚创建出来的子进程的id #os.getpid()是父进程的PID 用ps -aux 查看就只到了 else: print("----子进程--%d-%d-"%(os.getpid(),os.getppid())) #os.getpid()是子进程PID,os.getppid()是父进程的PID # 运行结果 1635 ----父进程--1634-- 0 ----子进程--1635-1634-
-
先退出
import os import time ret = os.fork() if ret == 0: print("----子进程----") time.sleep(5) print("----子进程over----",end="") else: print("----父进程----") time.sleep(3) print("----over----") #主进程(父进程)结束,那么终端直接给提示 不会因为你的子进程没有结束而等它 #但是也不会因为你的主进程结束而结束子进程 # 运行结果 ----父进程---- ----子进程---- ----over---- zhangshengxiaodeMacBook-Air:01.进程程序 xiaoge$ ----子进程over--------over----
-
修改全局变量
import os import time g_num = 100 ret = os.fork() #每一个进程都是个单独不共享的 所以这里子进程把全局变量改了 #主进程的全局变量没变 #所以这里的所有内容都不共享 每个进程都有个这份内容 不管那个进程修改了里面 #的内容都不影响其他的进程内容 if ret == 0: print("----process-1----") g_num += 1 print("----process-1 g_num = %d"%g_num) else: time.sleep(3) print("----process-2----") print("----process-2 g_num = %d"%g_num) # 运行结果 ----process-1---- ----process-1 g_num = 101 ----process-2---- ----process-2 g_num = 100
-
多次fork-1
import os #父进程 ret = os.fork() if ret == 0: #子进程 print("----1----") else: #父进程 print("----2----") #父子进程 ret = os.fork() if ret == 0: #孙子 #2儿子 print("----11----") else: #儿子 #父进程 print("----22----") # 运行结果 ----2---- ----22---- ----1---- ----11---- ----22---- ----11----
-
多次fork-2
import os #父进程 ret = os.fork() if ret == 0: #子进程 print("----1----") else: #父进程 print("----2----") ret = os.fork() if ret == 0: #2儿子 print("----11----") else: #父进程 print("----22----") # 运行结果 ----2---- ----22---- ----1---- ----11----
-
3-fork
import os os.fork() os.fork() os.fork() """ #下面是fork炸弹,不相信你可以执行下看看 while True: os.fork() """ print("----1----") # 运行结果 ----1---- ----1---- ----1---- ----1---- ----1---- ----1---- ----1---- ----1----
-
Process创建进程
from multiprocessing import Process #Process 是个类 import time def test(): while True: print("----test----") time.sleep(1) p = Process(target=test) #target指向谁 这个进程就执行谁 p.start() #让这个进程开始执行test函数里的代码 while True: print("----main----") time.sleep(1) # 运行结果 ----main---- ----test---- ----test---- ----main---- ----test---- ----main---- ----test---- ----main---- ----test---- ----main---- 死循环
-
Process创建的子进程和主进程的结束
from multiprocessing import Process #Process 是个类 import time def test(): for i in range(5): print("----test----") time.sleep(1) p = Process(target=test) #target指向谁 这个进程就执行谁 p.start() #让这个进程开始执行test函数里的代码 # 所有子进程结束后 主进程才结束 这就是和fork的区别 # 运行结果 ----test---- ----test---- ----test---- ----test---- ----test----
-
join子进程
from multiprocessing import Process import random import time def test(): for i in range(random.randint(1,5)): print("----%d----"%i) time.sleep(1) p = Process(target=test) p.start() #等待p.start() 进程执行完 p.join()#堵塞(等待子进程执行完了 在执行主进程) #在join()这个括号里写1就是等待子进程1秒 看你写几就等待几秒 print("----main----") # 运行结果 ----0---- ----main----
-
Process子类创建进程
from multiprocessing import Process import time class MyNewProcess(Process): def run(self): #从写父类的run方法 父类里的run方法是个接口 while True: print("----1----") time.sleep(1) p = MyNewProcess() p.start() while True: print("----main----") time.sleep(1) # 运行结果 ----main---- ----1---- ----main---- ----1---- ----1---- ----main---- ----1---- ----main---- ----1---- ----main---- ----1---- ----main---- ----1---- ----main---- 死循环
-
Process类的run方法
from multiprocessing import Process import time class MyNewProcess(Process): pass p = MyNewProcess() p.start() #父类里 的run方法只是个接口 你可以在子类里从写run方法 while True: print("----main----") time.sleep(1) # 运行结果 ----main---- ----main---- ----main---- ----main---- ----main---- ----main---- ----main---- 死循环
-
Process子类创建完整版
#创建新的进程还能够使用类的方式,可以自定义一个类,继承Process类,每次实例化这个类的时候,就等同于实例化一个进程对象,请看下面的实例: from multiprocessing import Process import time import os #继承Process类 class Process_Class(Process): #因为Process类本身也有__init__方法,这个子类相当于重写了这个方法, #但这样就会带来一个问题,我们并没有完全的初始化一个Process类,所以就不能使用从这个类继承的一些方法和属性, #最好的方法就是将继承类本身传递给Process.__init__方法,完成这些初始化操作 def __init__(self,interval): Process.__init__(self) self.interval = interval #重写了Process类的run()方法 def run(self): print("子进程(%s) 开始执行,父进程为(%s)"%(os.getpid(),os.getppid())) t_start = time.time() time.sleep(self.interval) t_stop = time.time() print("(%s)执行结束,耗时%0.2f秒"%(os.getpid(),t_stop-t_start)) if __name__=="__main__": t_start = time.time() print("当前程序进程(%s)"%os.getpid()) p1 = Process_Class(2) #对一个不包含target属性的Process类执行start()方法,就会运行这个类中的run()方法,所以这里会执行p1.run() p1.start() p1.join() t_stop = time.time() print("(%s)执行结束,耗时%0.2f"%(os.getpid(),t_stop-t_start)) # 运行结果 当前程序进程(1783) 子进程(1784) 开始执行,父进程为(1783) (1784)执行结束,耗时2.00秒 (1783)执行结束,耗时2.01
-
进程池Pool
#初始化Pool时,可以指定一个最大进程数,当有新的请求提交到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---- 0开始执行,进程号为1797 1开始执行,进程号为1798 2开始执行,进程号为1799 1 执行完毕,耗时0.33 3开始执行,进程号为1798 3 执行完毕,耗时0.23 4开始执行,进程号为1798 2 执行完毕,耗时0.76 5开始执行,进程号为1799 0 执行完毕,耗时0.95 6开始执行,进程号为1797 6 执行完毕,耗时0.08 7开始执行,进程号为1797 5 执行完毕,耗时0.48 8开始执行,进程号为1799 8 执行完毕,耗时0.33 9开始执行,进程号为1799 4 执行完毕,耗时1.15 9 执行完毕,耗时0.69 7 执行完毕,耗时1.87 -----end-----
-
进程池-apply_async
from multiprocessing import Pool import os import time def worker(num): for i in range(5): print("===pid=%d==num=%d="%(os.getpid(),num)) time.sleep(1) #3表示 进程池中最多有3个进程一起执行 pool = Pool(3) #这个池子最多一次完成3个任务 for i in range(10): # print("----%d----"%i) # time.sleep(1) #向进程池中添加任务 #注意:如果添加的任务数量超过了 进程池中进程的个数的话,那么不会导致添加不进入 # 添加到进程中的任务 如果还没有被执行的话,那么此时 他们会等待进程池中的 # 进程完成一个任务之后,会自动的去用刚刚的那个进程 完成当前的任务 pool.apply_async(worker,(i,)) #传参数 必须是元组 #apply_async 这是一个非堵塞方式(不用等,直接添加到进程池满为止) pool.close() #关闭进程池,相当于 不能再次添加新任务了 pool.join()#主进程 创建/添加 任务后,主进程 默认不会等待进程池中的任务执行玩后才结束 #而是 当主进程的任务做完之后 立马结束,,,,如果这个地方没join,会导致进程池中 #的任务不会执行 # 运行结果 ===pid=1808==num=0= ===pid=1809==num=1= ===pid=1810==num=2= ===pid=1808==num=0= ===pid=1809==num=1= ===pid=1810==num=2= ===pid=1809==num=1= ===pid=1808==num=0= ===pid=1810==num=2= ===pid=1810==num=2= ===pid=1809==num=1= ===pid=1808==num=0= ===pid=1808==num=0= ===pid=1810==num=2= ===pid=1809==num=1= ===pid=1808==num=3= ===pid=1810==num=4= ===pid=1809==num=5= ===pid=1808==num=3= ===pid=1810==num=4= ===pid=1809==num=5= ===pid=1810==num=4= ===pid=1809==num=5= ===pid=1808==num=3= ===pid=1810==num=4= ===pid=1808==num=3= ===pid=1809==num=5= ===pid=1809==num=5= ===pid=1808==num=3= ===pid=1810==num=4= ===pid=1809==num=6= ===pid=1810==num=7= ===pid=1808==num=8= ===pid=1809==num=6= ===pid=1810==num=7= ===pid=1808==num=8= ===pid=1808==num=8= ===pid=1810==num=7= ===pid=1809==num=6= ===pid=1809==num=6= ===pid=1808==num=8= ===pid=1810==num=7= ===pid=1808==num=8= ===pid=1810==num=7= ===pid=1809==num=6= ===pid=1808==num=9= ===pid=1808==num=9= ===pid=1808==num=9= ===pid=1808==num=9= ===pid=1808==num=9=
-
进程池-apply
from multiprocessing import Pool import os import time def worker(num): for i in range(5): print("===pid=%d==num=%d="%(os.getpid(),num)) time.sleep(1) #3表示 进程池中最多有3个进程一起执行 pool = Pool(3) #这个池子最多一次完成3个任务 for i in range(10): print("----%d----"%i) pool.apply(worker,(i,)) #传参数 必须是元组 #apply 这是一个堵塞方式(主进程运行到这不动了,等待子进程的任务完成,在运行一个子任务) pool.close() #关闭进程池,相当于 不能再次添加新任务了 pool.join()#主进程 创建/添加 任务后,主进程 默认不会等待进程池中的任务执行玩后才结束 #而是 当主进程的任务做完之后 立马结束,,,,如果这个地方没join,会导致进程池中 #的任务不会执行 # 运行结果 ----0---- ===pid=1823==num=0= ===pid=1823==num=0= ===pid=1823==num=0= ===pid=1823==num=0= ===pid=1823==num=0= ----1---- ===pid=1824==num=1= ===pid=1824==num=1= ===pid=1824==num=1= ===pid=1824==num=1= ===pid=1824==num=1= ----2---- ===pid=1825==num=2= ===pid=1825==num=2= ===pid=1825==num=2= ===pid=1825==num=2= ===pid=1825==num=2= ----3---- ===pid=1823==num=3= ===pid=1823==num=3= ===pid=1823==num=3= ===pid=1823==num=3= ===pid=1823==num=3= ----4---- ===pid=1824==num=4= ===pid=1824==num=4= ===pid=1824==num=4= ===pid=1824==num=4= ===pid=1824==num=4= ----5---- ===pid=1825==num=5= ===pid=1825==num=5= ===pid=1825==num=5= ===pid=1825==num=5= ===pid=1825==num=5= ----6---- ===pid=1823==num=6= ===pid=1823==num=6= ===pid=1823==num=6= ===pid=1823==num=6= ===pid=1823==num=6= ----7---- ===pid=1824==num=7= ===pid=1824==num=7= ===pid=1824==num=7= ===pid=1824==num=7= ===pid=1824==num=7= ----8---- ===pid=1825==num=8= ===pid=1825==num=8= ===pid=1825==num=8= ===pid=1825==num=8= ===pid=1825==num=8= ----9---- ===pid=1823==num=9= ===pid=1823==num=9= ===pid=1823==num=9= ===pid=1823==num=9= ===pid=1823==num=9=
-
进程间通信-Queue的使用
#可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息列队程序,首先用一个小实例来演示一下Queue的工作原理: #coding=utf-8 from multiprocessing import Queue q=Queue(3) #初始化一个Queue对象,最多可接收三条put消息 q.put("消息1") q.put("消息2") print(q.full()) #False q.put("消息3") print(q.full()) #True #因为消息列队已满下面的try都会抛出异常,第一个try会等待2秒后再抛出异常,第二个Try会立刻抛出异常 try: q.put("消息4",True,2) except: print("消息列队已满,现有消息数量:%s"%q.qsize()) try: q.put_nowait("消息4") except: print("消息列队已满,现有消息数量:%s"%q.qsize()) #推荐的方式,先判断消息列队是否已满,再写入 if not q.full(): q.put_nowait("消息4") #读取消息时,先判断消息列队是否为空,再读取 if not q.empty(): for i in range(q.qsize()): print(q.get_nowait()) # 运行结果 False True 消息列队已满,现有消息数量:3 消息列队已满,现有消息数量:3 消息1 消息2 消息3
-
进程间通信-Queue的实列
from multiprocessing import Process, Queue import os, time, random # 写数据进程执行的代码: def write(q): for value in ['A', 'B', 'C']: print('Put %s to queue...'%value) q.put(value) time.sleep(random.random()) # 读数据进程执行的代码: def read(q): while True: if not q.empty(): value = q.get(True) print('Get %s from queue.'%value) time.sleep(random.random()) else: break if __name__=='__main__': # 父进程创建Queue,并传给各个子进程: q = Queue() pw = Process(target=write, args=(q,)) pr = Process(target=read, args=(q,)) # 启动子进程pw,写入: pw.start() # 等待pw结束: pw.join() # 启动子进程pr,读取: pr.start() pr.join() # pr进程里是死循环,无法等待其结束,只能强行终止: print('') print('所有数据都写入并且读完') # 运行结果 Put A to queue... Put B to queue... Put C to queue... Get A from queue. Get B from queue. Get C from queue. 所有数据都写入并且读完
-
进程间通信-进程池中的Queue
#coding=utf-8 #修改import中的Queue为Manager from multiprocessing import Manager,Pool import os,time,random def reader(q): print("reader启动(%s),父进程为(%s)"%(os.getpid(),os.getppid())) for i in range(q.qsize()): print("reader从Queue获取到消息:%s"%q.get(True)) def writer(q): print("writer启动(%s),父进程为(%s)"%(os.getpid(),os.getppid())) for i in "dongGe": q.put(i) if __name__=="__main__": print("(%s) start"%os.getpid()) q=Manager().Queue() #使用Manager中的Queue来初始化 po=Pool() #使用阻塞模式创建进程,这样就不需要在reader中使用死循环了,可以让writer完全执行完成后,再用reader去读取 po.apply(writer,(q,)) po.apply(reader,(q,)) po.close() po.join() print("(%s) End"%os.getpid()) # 运行结果 (2105) start writer启动(2107),父进程为(2105) reader启动(2109),父进程为(2105) reader从Queue获取到消息:d reader从Queue获取到消息:o reader从Queue获取到消息:n reader从Queue获取到消息:g reader从Queue获取到消息:G reader从Queue获取到消息:e (2105) End
-
多种创建进程的方法比较
ret = os.fork() if ret == 0: #子进程 else: #父进程 #这个建议别用 因为它只支持 Mac Linux Uiux p1 = Process(target=xxx) p1.start() #父子进程都可以完成任务 pool = Pool(3) pool.apply_async(xxx) #主进程用来等待 , , , , 真正的任务都在子进程中执行
-
Process类的方法
Process语法结构如下 Process([group[,target[,name,[,args[,kwargs]]]]]) 1. target:表示这个进程实列所调用的对象 2. args:表示调用对象的位置参数元组 3. kwargs:表示调用对象的关键字参数字典 4. name:为当前进程实列的别名 5. group:大多数情况下用不到 Process常用方法 1. is_alive():判断进程实列是否还在执行 2. join([timeout]):是否等待进程实列执行结束,或等待多少秒 3. start():启动进程实列(创建子进程) 4. run():如果没有给定target参数,对这个对象调用start()方法时.就将执行对象中的run()方法 5. terminate():不管任务是否完成,立即终止 Process常用属性 1. name:当前进程实列别名,默认为Process-N,N为从1开始递增的整数 2. pid:当前进程实列的PID值
-
Queue说明
初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的尽头); Queue.qsize():返回当前队列包含的消息数量; Queue.empty():如果队列为空,返回True,反之False ; Queue.full():如果队列满了,返回True,反之False; Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True; 1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出"Queue.Empty"异常; 2)如果block值为False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常; Queue.get_nowait():相当Queue.get(False); Queue.put(item,[block[, timeout]]):将item消息写入队列,block默认值为True; 1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出"Queue.Full"异常; 2)如果block值为False,消息列队如果没有空间可写入,则会立刻抛出"Queue.Full"异常; Queue.put_nowait(item):相当Queue.put(item, False)
多进程拷贝文件
-
copyFile
from multiprocessing import Pool,Manager import os def copyFileTask(fileName,oldFolderName,newFolderName,queue): """完成拷贝一个文件的功能""" fr = open(oldFolderName+"/"+fileName) fw = open(newFolderName+"/"+fileName,"w") content = fr.read() fw.write(content) fr.close() fw.close() queue.put(fileName) def main(): #0.获取用户要copy的文件夹的名字 oldFolderName = input("请输入原文件夹的名字:") #1.创建一个文件夹 newFolderName = oldFolderName+"-复件" #print(newFolderName) os.mkdir(newFolderName) #2.获取old的文件夹中的所有的文件名字 fileNames = os.listdir(oldFolderName) #print(fileNames) #3.使用多进程的方式copy原文件中的所有文件到新的文件夹中 pool = Pool(5) queue = Manager().Queue() for name in fileNames: pool.apply_async(copyFileTask,args=(name,oldFolderName,newFolderName,queue)) num = 0 allNum = len(fileNames) while True: queue.get() num += 1 copyRate = num/allNum print("\rcopy的进度是:%.2f%%"%(copyRate*100),end="") if num == allNum: break print("\n已完成copy.....") pool.close() pool.join() if __name__ == "__main__": main()
僵尸进程:子进程死了父进程没给它收尸
孤儿进程:父进程死了子进程还是活的,这个孤儿进程是操作系统的pid为1的那个进程给它收尸的