一.os模块中的fork方法(只在linux系统中使用,Windows系统不可用)
Python在os模块上封装了常用的系统调用,其中就包括了fork,我们可以很轻松地在Python代码中创建进程。
import os, time def sing(): for x in range(5): print("在唱歌") time.sleep(1) def network(): for x in range(5): print("在上网") time.sleep(1) # 注意:os模块下的fork()方法在Windows系统中无法使用,只能在Linux系统中使用,比如 Ubuntu 15.04 res = os.fork() if res == 0: sing() else: network() print("这个程序会执行两次")Python中的fork() 函数可以获得系统中进程的PID ( Process ID ),返回0则为子进程,否则就是父进程,然后可以据此对运行中的进程进行操作;
但是强大的 fork() 函数在Windows版的Python中是无法使用的。。。只能在Linux系统中使用,比如 Ubuntu 15.04,Windows中获取父进程ID可以用 getpid()。
os.getpid()、os.getppid()(获得当前进程编号、获得父进程编号)
我们可以使用os模块的getpid来获取当前进程的进程编号,同样也可以使用os.getppid()方法案来获取当前进程的父进程编号。
import os import time # 使用os模块的fork方法可以创建一个新的进程 pid = os.fork() if pid == 0: while True: print("我是子线程,我的编号是%s,我的父进程编号是%s" %(os.getpid(),os.getppid())) time.sleep(1) else: while True: print("我是父线程,我的编号是%s,我的子进程编号是%s" %(os.getpid(), pid)) time.sleep(1) |
使用os模块中的getpid()方法,可以得到当前线程的编号,使用getppid()方法可以得到该线程的父级编号。
二、multiprocessing模块下的Process类实现多进程(通用)
前面我们使用os.fork()方法实现了多进程,但是这种方案只能在Linux下运行,window环境下是无法运行的,那么有没有可以实现在任何平台都能运行的多进程了,有!Python为大家提供了multiprocessing模块用来实现多进程。
(1)函数实现方式
# 1.函数实现多进程——无参版 from multiprocessing import Process def run(): print("这是一个子进程") if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run) t1.start() print("============ main end =============") ''' 运行结果: ++++++++++++ main start +++++++++++++ ============ main end ============= 这是一个子进程 ''' # 2.函数实现多进程——有参版 from multiprocessing import Process def run1(msg): print("这是一个有参数的子进程,参数为: %s"%msg) if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run1,args=("嘿嘿",)) # args为调用的子进程的函数的参数,注意类型是一个元组或者列表。t1.start()
print("============ main end =============") ''' 运行结果为: ++++++++++++ main start +++++++++++++ ============ main end ============= 这是一个有参数的子进程,参数为: 嘿嘿 ''' # 3.多个进程同一函数运行先后顺序,顺序无法确定 from multiprocessing import Process import time def run2(msg): for x in range(3): print("这是一个有参数的子进程,参数为: %s"%msg) time.sleep(1) # 人为的让代码停顿,是其他进程有机会抢入 if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run2,args=("嘿嘿",)) t1.start() t2 = Process(target=run2, args=("哈哈",)) t2.start() t3 = Process(target=run2, args=("呵呵",)) t3.start() print("============ main end =============") '''运行结果: ++++++++++++ main start +++++++++++++ ============ main end ============= 这是一个有参数的子进程,参数为: 哈哈 这是一个有参数的子进程,参数为: 嘿嘿 这是一个有参数的子进程,参数为: 呵呵 这是一个有参数的子进程,参数为: 哈哈 这是一个有参数的子进程,参数为: 嘿嘿 这是一个有参数的子进程,参数为: 呵呵 这是一个有参数的子进程,参数为: 嘿嘿 这是一个有参数的子进程,参数为: 哈哈 这是一个有参数的子进程,参数为: 呵呵 ''' # 4.多函数多进程,顺序依然无法确定 from multiprocessing import Process import time def run3(msg): for x in range(3): print("这是第一个有参数的子进程,参数为: %s111"%msg) time.sleep(1) # 人为的让代码停顿,是其他进程有机会抢入 def run4(msg): for x in range(3): print("这是第二个有参数的子进程,参数为: %s222" % msg) time.sleep(1) def run5(msg): for x in range(3): print("这是第三个有参数的子进程,参数为: %s333" % msg) time.sleep(1) if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run3,args=("嘿嘿",)) t1.start() t2 = Process(target=run4, args=("哈哈",)) t2.start() t3 = Process(target=run5, args=("呵呵",)) t3.start() print("============ main end =============") ''' 运行结果: ++++++++++++ main start +++++++++++++ ============ main end ============= 这是第二个有参数的子进程,参数为: 哈哈222 这是第一个有参数的子进程,参数为: 嘿嘿111 这是第三个有参数的子进程,参数为: 呵呵333 这是第一个有参数的子进程,参数为: 嘿嘿111 这是第二个有参数的子进程,参数为: 哈哈222 这是第三个有参数的子进程,参数为: 呵呵333 这是第一个有参数的子进程,参数为: 嘿嘿111 这是第二个有参数的子进程,参数为: 哈哈222 这是第三个有参数的子进程,参数为: 呵呵333 ''' # 5.让主进程等待子进程 from multiprocessing import Process def run1(msg): print("这是一个有参数的子进程,参数为: %s"%msg) if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run1,args=("嘿嘿",)) t1.start() t1.join() # join方法表示只有子进程执行完成后,主进程才能结束。主进程会等待子进程完成后,自身才会执行完成。 print("============ main end =============") ''' 运行结果为: ++++++++++++ main start +++++++++++++ 这是一个有参数的子进程,参数为: 嘿嘿 ============ main end ============= ''' (2)类实现方式# 1.无参数型,定义一个类,使其继承自Process类,重写run方法即可 from multiprocessing import Process class MyProcess(Process): def run(self): print("这是类实现的子进程") if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") myprocess = MyProcess() myprocess.start() print("============ main end ================") ''' 运行结果: ++++++++++++ main start +++++++++++++ ============ main end ================ 这是类实现的子进程 ''' # 2.有参数型 from multiprocessing import Process class MyProcess(Process): def __init__(self,name,msg): super().__init__(name=name) self.msg = msg def run(self): print("这是类实现的子进程") print(self.name) print(self.msg) if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") myprocess = MyProcess("子进程名称","参数内容") myprocess.start() print("============ main end ================") ''' 运行结果: ++++++++++++ main start +++++++++++++ ============ main end ================ 这是类实现的子进程 子进程名称 参数内容 '''三、进程池Poolfrom multiprocessing import Pool def run(): print("这是一个子进程") return 0 def run1(): print("这是另一个子进程") return 1 def cb(msg): print("这是一个回调函数,回调函数的参数来自子进程的返回值,返回值为%s"%msg) if __name__ == '__main__': print("+++++++++++ main start +++++++++++") pool = Pool(3) # 可以设定提前创建的子进程的数目,一般根据项目需求确定 for x in range(3): pool.apply_async(func=run,callback=cb) # callback为回调函数,子进程结束后才会执行 pool.apply_async(func=run1, callback=cb) pool.close() # 一定要先关闭,后join() pool.join() print("=========== main end ============") ''' 运行结果: +++++++++++ main start +++++++++++ 这是一个子进程 这是另一个子进程 这是一个回调函数,回调函数的参数来自子进程的返回值,返回值为0 这是一个子进程 这是一个回调函数,回调函数的参数来自子进程的返回值,返回值为1 这是一个回调函数,回调函数的参数来自子进程的返回值,返回值为0 这是另一个子进程 这是一个回调函数,回调函数的参数来自子进程的返回值,返回值为1 这是一个子进程 这是一个回调函数,回调函数的参数来自子进程的返回值,返回值为0 这是另一个子进程 这是一个回调函数,回调函数的参数来自子进程的返回值,返回值为1 =========== main end ============ '''四、消息队列Queue\Pipe管道\manager实现进程间的通讯(进程间原本无法通讯,即便是全局变量也是各自使用,不会共享)注意:一般我们使用apply_async这个方法,表示非阻塞的运行,一旦使用了apply方法表示阻塞式执行任务,此时就是单任务执行了(一般不会使用,特殊场景才会使用)
(1)消息队列Queue我们可以使用multiprocessing模块中的Queue(消息队列)来完成多进程间的数据传递
我们可以通过queue获取队列对象,队列对象的常用方法如下:
q.put() q.get() q.get(item,block=True,timeout=None) q.put(item,block=True,timeout=None) q.empty() q.full() q.qsize() q.put_nowait() q.get_nowait() |
from multiprocessing import Process, Pool, Queue # Queue队列的特征:先进先出,注意queue是线程的队列,不同于Queue import time def sendMsg(q,msg): while True: print("发送数据:%s>>>>>>>>>>>>>>>>>>>>>>" % msg) q.put(msg) time.sleep(1) def accept(q): while True: print("<<<<<<<<<<<<<<<<<<<<<接收到的数据为:%s"%q.get()) time.sleep(1) if __name__ == '__main__': q = Queue(5) # 表示最多可以推进消息的数量 new_time = time.time() print("++++++++++++++++++ main start +++++++++++++++++++++") t1 = Process(target=sendMsg, args=(q,"你好吗?"), name="发送数据进程") t1.start() t2 = Process(target=accept,args=(q,), name="接收数据进程") t2.start() print("================== main end ======================", time.time() - new_time)
''' 运行结果: ++++++++++++++++++ main start +++++++++++++++++++++ ================== main end ====================== 0.03002023696899414 发送数据:你好吗?>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<接收到的数据为:你好吗? 发送数据:你好吗?>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<接收到的数据为:你好吗? 发送数据:你好吗?>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<接收到的数据为:你好吗? '''(2)Pipe管道
from multiprocessing import Process,Pipe import time def sendMsg(p,msg): print("发送数据:%s>>>>>>>>>>>>>>>>>>>>>>" % msg) p.send(msg) p.close() time.sleep(1) if __name__ == '__main__': p1,p2 = Pipe() # Pipe管道返回值有两个,一个是父进程,一个是子进程 print(p1,p2) # 可以将p1,p2打印出来看看 new_time = time.time() print("++++++++++++++++++ main start +++++++++++++++++++++") t1 = Process(target=sendMsg, args=(p1,"你好吗?"), name="发送数据进程") t1.start() print("<<<<<<<<<<<<<<<接收到的数据为:%s"%p2.recv()) print("================== main end ======================", time.time() - new_time) ''' 运行结果: <multiprocessing.connection.PipeConnection object at 0x0000023B3CDC1F28> <multiprocessing.connection.PipeConnection object at 0x0000023B3CBE72B0> ++++++++++++++++++ main start +++++++++++++++++++++ 发送数据:你好吗?>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<接收到的数据为:你好吗? ================== main end ====================== 0.2751955986022949 '''(3)manager
之前我们学习进程间的数据通信仅仅只是数据的传递,而不是数据的共享,那么如果我们想实现进程间的数据共享应该怎么做呢?使用Manager来实现。
Managers支持的数据类型有list、dict、Namespace、Lock、Rlock、Queue、Value、Array and so on。
from multiprocessing import Process, Manager def saveDatas(lists, dicts): lists.append("武松") lists.append("潘金莲") lists.append("武大郎") dicts["name"] = "姜子牙" dicts["age"] = 80 dicts["mp"] = 50 print(lists) print(dicts) if __name__ == '__main__': print("++++++++++++++ main start +++++++++++++++++++") # manager = Manager() # 获取一个Manager对象 with Manager() as manager: # <==>manager = Manager() lists = manager.list() # 普通的list无法跨越多进程,只有manager中的list可以 dicts = manager.dict() ls = [] # 启动线程 for x in range(5): task = Process(target=saveDatas, args=(lists, dicts)) task.start() ls.append(task) # 如果join()方法写在这里,则是一个进程结束后才开始第二个进程,进程之间数据同步,类似于单进程 # for i in ls: i.join() # manager 也要借助于join()方法来迫使主进程等待子进程的运行 print("================ main end ================") ''' 运行结果:++++++++++++++ main start +++++++++++++++++++ ['武松', '潘金莲', '武大郎'] {'age': 80, 'mp': 50, 'name': '姜子牙'} ['武松', '潘金莲', '武大郎', '武松', '潘金莲', '武大郎'] {'age': 80, 'mp': 50, 'name': '姜子牙'} ['武松', '潘金莲', '武大郎', '武松', '潘金莲', '武大郎', '武松', '潘金莲', '武大郎'] {'age': 80, 'mp': 50, 'name': '姜子牙'} ['武松', '潘金莲', '武大郎', '武松', '潘金莲', '武大郎', '武松', '潘金莲', '武大郎', '武松', '潘金莲', '武大郎'] {'age': 80, 'mp': 50, 'name': '姜子牙'} ['武松', '潘金莲', '武大郎', '武松', '潘金莲', '武大郎', '武松', '潘金莲', '武大郎', '武松', '潘金莲', '武大郎', '武松', '潘金莲', '武大郎'] {'age': 80, 'mp': 50, 'name': '姜子牙'} ================ main end ================ '''