python 多进程

python 多进程

一、创建多进程的基本法方法

创建进程的类:Process([group [, target [, name [, args [, kwargs]]]]]),target表示调用对象,args表示调用对象的位置参数元组。kwargs表示调用对象的字典。name为别名。group实质上不使用。

 

1、使用现成的Process类创建多线程

import multiprocessing
import time

def worker(interval):
    n = 5
    while n > 0:
        print("The time is {0}".format(time.ctime()))
        time.sleep(interval)
        n -= 1

if __name__ == "__main__":
    p = multiprocessing.Process(target = worker, args = (3,))
    p.start()
    print "p.pid:", p.pid
    print "p.name:", p.name
    print "p.is_alive:", p.is_alive()

 

输出结果:
p.pid: 8736
p.name: Process-1
p.is_alive: True
The time is Tue Apr 21 20:55:12 2015
The time is Tue Apr 21 20:55:15 2015
The time is Tue Apr 21 20:55:18 2015
The time is Tue Apr 21 20:55:21 2015
The time is Tue Apr 21 20:55:24 2015

 

二、使用自定义的类创建多线程

import multiprocessing
import time

class MyProcess(multiprocessing.Process):
    def __init__(self, interval):
        multiprocessing.Process.__init__(self)
        self.interval = interval

    def run(self):
        n = 5
        while n > 0:
            print("the time is {0}".format(time.ctime()))
            time.sleep(self.interval)
            n -= 1

if __name__ == '__main__':
    p = MyProcess(3)
    p.start()      
输出结果:
the time is Wed Jul 20 22:44:16 2016
the time is Wed Jul 20 22:44:19 2016
the time is Wed Jul 20 22:44:22 2016
the time is Wed Jul 20 22:44:25 2016
the time is Wed Jul 20 22:44:28 2016

 

说明:自定义多线程类需要重写run方法,执行自定义类的实例时会自动调用run方法。

 

3、守护进程

1)守护进程即守护主进程的进程,与主进程同生共死。

2)主进程退出时,守护进程也跟着退出。

3)默认情况下,创建的紫禁城程非守护进程,既主进程如果执行完毕的,而子进程没有执行完毕,主进程会等待子进程执行完毕后再退出。

4)设置守护进程的方法是 setDaemon = True。

 

def worker(interval):
    print("work start:{0}".format(time.ctime()));
    time.sleep(interval)
    print("work end:{0}".format(time.ctime()));

if __name__ == "__main__":
    p = multiprocessing.Process(target = worker, args = (3,))
    p.daemon = True
    p.start()
    print("end!")
输出结果:

end!

 

输出结果只有一个end!,子进程随着主进程的消亡而消亡,因为设置了守护进程。

 

4、进程间共享数据

默认情况下进程间不能共享数据

#-*-coding:utf8-*-
import multiprocessing
li = []

def foo(i):
    global li
    li.append(i)
    print('say hi', li)

if __name__ == '__main__':
    for i in range(10):
        p = multiprocessing.Process(target=foo, args=(i,))
        p.start()

    print('ending', li)
输出结果:
say hi [1]
say hi [0]
say hi [2]
say hi [3]
say hi [4]
say hi [5]
ending []
say hi [6]
say hi [8]
say hi [7]
say hi [9]

说明进程间没有共享数据

进程间共享内存空间的方法

方法一:使用multiprocess 自带的queues

from multiprocessing import Process
from multiprocessing import queues
import multiprocessing

def foo(i,arg):
    arg.put(i)
    print('say hi',i,arg.qsize())


if __name__ == "__main__":
    # li = []
    li = queues.Queue(20,ctx=multiprocessing)
    for i in range(10):
        p = Process(target=foo,args=(i,li,))
        #p.daemon = True
        p.start()
        #p.join()
输出结果:
say hi 7 2
say hi 6 3
say hi 2 3
say hi 5 4
say hi 1 6
say hi 3 6
say hi 4 8
say hi 0 8
say hi 9 9
say hi 8 10

 

说明:从输出结果中可以看到 队列的大小是在不断变化的,从而说明各个进程进程建共享了队列的数据。

 

方法二:使用multiprocessing的数据结构 Array

from multiprocessing import Process
from multiprocessing import Array

def foo(i,arg):
    arg[i] = i + 100
    for item in arg:
        print(item)
    print('================')

if __name__ == "__main__":
    li = Array('i', 3)
    for i in range(3):
        p = Process(target=foo,args=(i,li,))
        p.start()
输出结果:
0
0
102
================
0
101
102
================
100
101
102
================

 

说明:默认情况下 Array 初始化状态下,是一组内存地址连续的,数据类型相同的,初始值是0的一组数据。我们看到在多个进程的的作用下,Array 不同位置的元素,被连续修改。说明多个进程建共享了内存。

方法三:使用multiprocess的内置字典

from multiprocessing import Process
from multiprocessing import Manager
import multiprocessing


def foo(i,arg):
    arg[i] = i + 100
    print(arg.values())

if __name__ == "__main__":
    obj = Manager()
    li = obj.dict()
    for i in range(10):
        p = Process(target=foo,args=(i,li,))
        p.start()
        p.join()
 
输出结果:
[100]
[100, 101]
[100, 101, 102]
[100, 101, 102, 103]
[100, 101, 102, 103, 104]
[100, 101, 102, 103, 104, 105]
[100, 101, 102, 103, 104, 105, 106]
[100, 101, 102, 103, 104, 105, 106, 107]
[100, 101, 102, 103, 104, 105, 106, 107, 108]
[100, 101, 102, 103, 104, 105, 106, 107, 108, 109]

 

说明:从输出结果上看,字典的值是不断增加的,说明多个进程间共享了字典的内存空间。

 

进程池

进程池会把进程的最大数量控制在一个值,进程池可以提供指定数量的进程供用户调用,当有新的请求提交到进程池中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果进程池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。

1、使用阻塞的进程池

import multiprocessing
import time

def func(msg):
    print("msg:", msg)
    time.sleep(2)
    print("end")

if __name__ == "__main__":
    pool = multiprocessing.Pool(processes=3)
    for i in range(5):
        msg = "mark %d" % i
        pool.apply(func, (msg, ))   #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去

    print("proessed here ##################")
    pool.close()
    pool.join() #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数使主进程阻塞,等待所有子进程结束
    print("done.")
输出结果:
msg: mark 0
end
msg: mark 1
end
msg: mark 2
end
msg: mark 3
end
msg: mark 4
end
proessed here ##################
done.

 

2、使用异步的进程池(非阻塞)

import multiprocessing
import time

def func(msg):
    print("msg:", msg)
    time.sleep(2)
    print("end")

if __name__ == "__main__":
    pool = multiprocessing.Pool(processes=3)
    for i in range(5):
        msg = "mark %d" % i
        pool.apply_async(func, (msg, ))   #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去

    print("proessed here ##################")
    pool.close()
    pool.join() #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数使主进程阻塞,等待所有子进程结束
    print("done.")
输出结果:
proessed here ##################
msg: mark 0
msg: mark 1
msg: mark 2
end
msg: mark 3
end
msg: mark 4
end
end
end
done.

 

相关函数说明:

1、apply_async(func[, args[, kwds[, callback]]]) 

与apply用法一致,但它是非阻塞的且支持结果返回后进行回调。

主进程循环运行过程中不等待apply_async的返回结果,在主进程结束后,即使子进程还未返回整个程序也会退出。虽然 apply_async是非阻塞的,但其返回结果的get方法却是阻塞的,如使用result.get()会阻塞主进程。
如果我们对返回结果不感兴趣, 那么可以在主进程中使用pool.close与pool.join来防止主进程退出。注意join方法一定要在close或terminate之后调用。

 

2、close() 
关闭pool,使其不再接受新的任务。

 

3、terminate() 
结束工作进程,不再处理未处理的任务。

 

4、join() 
主进程阻塞等待子进程的退出, join方法要在close或terminate之后使用。

 

3、获取进程池中进程的返回结果

import multiprocessing
import time

def func(msg):
    print("msg:", msg)
    time.sleep(3)
    print("end")
    return "done" + msg

if __name__ == "__main__":
    pool = multiprocessing.Pool(processes=4)
    for i in range(5):
        msg = "hello %d" % i
        print(pool.apply_async(func, (msg,)).get())
    pool.close()
    pool.join()
输出结果:
msg: hello 0
end
donehello 0
msg: hello 1
end
donehello 1
msg: hello 2
end
donehello 2
msg: hello 3
end
donehello 3
msg: hello 4
end
donehello 4

 

说明:我们看到,当获取进程池中进程的结果时,输出结果是阻塞的。正如上边apply_sync函数的解释,当要获取进程的结果时,执行的过程就会变成阻塞的。

 

posted @ 2016-07-20 23:00  9527chu  阅读(648)  评论(0编辑  收藏  举报