Python高级编程——12. (1)系统编程之多进程

一.os模块中的fork方法(只在linux系统中使用,Windows系统不可用)

Pythonos模块上封装了常用的系统调用,其中就包括了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.04Windows中获取父进程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  ================
这是类实现的子进程
子进程名称
参数内容
'''
三、进程池Pool

from 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 ============
'''

注意:一般我们使用apply_async这个方法,表示非阻塞的运行,一旦使用了apply方法表示阻塞式执行任务,此时就是单任务执行了(一般不会使用,特殊场景才会使用)

四、消息队列Queue\Pipe管道\manager实现进程间的通讯(进程间原本无法通讯,即便是全局变量也是各自使用,不会共享)
(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支持的数据类型有listdict、NamespaceLockRlockQueue、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 ================                 
'''

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值