xone

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

并发:一个处理器同时处理多个任务。

并行:多个处理器或者是多核的处理器同时处理多个不同的任务.

 

fork创建子进程

import os
import time

#fork出一个子进程,子进程也从这一行开始执行
ret = os.fork()
if ret == 0:
    while True:
        print("---1---")
        time.sleep(1)
else:
    while True:
        print("---2---")
        time.sleep(1)

  输出

---2---
---1---
---1---
---2---
---2---
---1---
---1---
---2---
...

  

查看子进程id

import os
import time

ret = os.fork()
if ret != 0:
    print("---父进程---%d---"%os.getpid())
else:  #ret等于0的是子进程
    print("---子进程---%d---父进程---%d---"%(os.getpid(), os.getppid()))

  输出

---父进程---5142---
---子进程---5143---父进程---5142---

  

全局变量在多个进程之间不共享

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

import os
import time

ret = os.fork()
if ret != 0:
    print("---1---")
else:
    print("---2---")

ret = os.fork()
if ret != 0:
    print("---11---")
else:
    print("---22---")

  输出

---1---
---2---
---11---
---22---
---22---
---11---

  

fork炸弹

import os
while True:
    os.fork()
print("---1---")

注意:

fork不能在windows下运行

fork创建的主进程不会等到子进程运行结束后再推出

 

 

process

Process语法结构如下:
Process([group[,target[,name[,args[,kwargs]]]]])
target:表示这个进程实例所调用对象;
args:表示调用对象的位置参数元组;
kwargs:表示调用对象的关键字参数字典;
name:为当前进程实例的别名;
group:大多数情况下用不到;

 

Process类常用方法:
is_alive():判断进程实例是否还在执⾏;
join([timeout]):是否等待进程实例执行结束,或等待多少秒;
start():启动进程实例(创建子进程);
run():如果没有给定target参数,对这个对象调用start()方法时,就将执 ⾏对象中的run()⽅法;
terminate():不管任务是否完成,立即终止;

 

Process类常用属性:
name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数;
pid:当前进程实例的PID值;

 

process创建子进程

 

process可以在windows上运行

from multiprocessing import Process

import time

def test():
    while True:
        print("---test---")
        time.sleep(1)


if __name__ == "__main__":
    p = Process(target=test)
    p.start()
    while True:
        print("---main---")
        time.sleep(1)

  输出

---main---
---test---
---main---
---test---
...

  

创建的子进程和主进程结束

from multiprocessing import Process
import time

def test():
    for i in range(5):
        print("---test---")
        time.sleep(1)
if __name__ == "__main__":
    p = Process(target=test)
    p.start() #让这个进程开始执行test函数里的代码
    print("---main---")

  输出

---main---
---test---
---test---
---test---
---test---
---test---

  

 给target函数传参数

from multiprocessing import Process
import os

def test(num):
    print("pid=%d,ppid=%d,num=%d"%(os.getpid(),os.getppid(),num))

if __name__ == "__main__":
    p = Process(target=test, args=(100,))
    p.start()
    print("---main-pid=%d---"%os.getpid())

  输出

---main-pid=14252---
pid=18284,ppid=14252,num=100

  

join

from multiprocessing import Process
import time

def test():
    for i in range(5):
        print("---%d---"%i)
        time.sleep(1)

if __name__ == "__main__":
    p = Process(target=test)
    p.start()
    p.join()#阻塞,子进程运行结束后,才向下继续执行
    print("---main---")

  输出

---0---
---1---
---2---
---3---
---4---
---main---

  

 第二种process创建子进程的方法

from multiprocessing import Process
import time

class MyNewProcess(Process):
    def run(self):
        while True:
            print("---1---")
            time.sleep(1)

if __name__ == "__main__":
    p = MyNewProcess()
    p.start()

    while True:
        print("---main---")
        time.sleep(1)

  输出

---main---
---1---
---main---
---1---
---main---
---1---
---main---
---1---
...

  

 进程池

from multiprocessing import Pool
import os
import time
def test(num):
    print("pid=%d,ppid=%d,num=%d"%(os.getpid(),os.getppid(),num))
    time.sleep(1)


if __name__ == "__main__":
    pool = Pool(3)

    for i in range(10):
        print("---%d---"%i)
        pool.apply_async(test,(i,))


    pool.close()
    pool.join() #join保证子进程运行结束后,进程池才退出

 

 

进程间通信-Queue
Process之间有时需要通信,操作系统提供了很多机制来实现进程间的通信。

可以使⽤multiprocessing模块的Queue实现多进程之间的数据传递,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);

实例一

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

  

实例二

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
如果要使⽤Pool创建进程,就需要使⽤multiprocessing.Manager()中的 Queue(),⽽不是multiprocessing.Queue(),否则会得到⼀条如下的错误信息:

# 修改import中的Queue为Manager
from multiprocessing import Manager, Pool
import os


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完全执行完
    po.apply(writer, (q,))
    po.apply(reader, (q,))
    po.close()
    po.join()
    print("(%s) End" % os.getpid())

  输出

(15004)	start 
writer启动(10232),父进程为(15004) 
reader启动(1612),父进程为(15004) 
reader从Queue获取到消息:d 
reader从Queue获取到消息:o 
reader从Queue获取到消息:n 
reader从Queue获取到消息:g 
reader从Queue获取到消息:G 
reader从Queue获取到消息:e 
(15004) End

  

  

  

 

posted on 2019-01-20 11:54  周小百  阅读(458)  评论(0编辑  收藏  举报