多进程multiprocessing

PACKAGE CONTENTS
    connection
    dummy (package)
    forking
    heap
    managers
    pool
    process
    queues
    reduction
    sharedctypes
    synchronize
    util
module package

the class frequently-used of the module:

1、Process

Process 类用来描述一个进程对象。创建子进程的时候,只需要传入一个执行函数和函数的参数即可完成 Process 示例的创建。

star() 方法启动进程,
join() 方法实现进程间的同步,等待所有进程退出。
close() 用来阻止多余的进程涌入进程池 Pool 造成进程阻塞。

class Process(__builtin__.object)
     |  Process objects represent activity that is run in a separate process
     |  
     |  The class is analagous to `threading.Thread`
     |  
     |  Methods defined here:
     |  
     |  __init__(self, group=None, target=None, name=None, args=(), kwargs={})
     |  
     |  __repr__(self)
     |  
     |  is_alive(self)
     |      Return whether process is alive
     |  
     |  join(self, timeout=None)
     |      Wait until child process terminates
     |  
     |  run(self)
     |      Method to be run in sub-process; can be overridden in sub-class
     |  
     |  start(self)
     |      Start child process
     |  
     |  terminate(self)
     |      Terminate process; sends SIGTERM signal or uses TerminateProcess()
Process Class
#1、设置daemon都为True
import multiprocessing
import time,datetime
def create_test_function(statement):
    time.sleep(2)
    print(statement)
if __name__ == "__main__":
    print("first")
    create_one_process = multiprocessing.Process(target=create_test_function,args=("good",))
    create_one_process.daemon = True
    create_one_process.start()
    print("second")
    create_two_process = multiprocessing.Process(target=create_test_function,args=("nice",))
    create_two_process.daemon = True
    create_two_process.start()
    print("third")
'''
output:
           first
           second
           third
'''

#2、设置daemon都为False
import multiprocessing
import time,datetime
def create_test_function(statement):
    time.sleep(2)
    print(statement)
if __name__ == "__main__":
    print("first")
    create_one_process = multiprocessing.Process(target=create_test_function,args=("good",))
    create_one_process.daemon = False
    create_one_process.start()
    print("second")
    create_two_process = multiprocessing.Process(target=create_test_function,args=("nice",))
    create_two_process.daemon = False
    create_two_process.start()
    print("third")
'''
output:
           first
           second
           third
           good
           nice
'''

#3、设置daemon一个True一个False
import multiprocessing
import time,datetime
def create_test_function(statement):
    time.sleep(2)
    print(statement)
if __name__ == "__main__":
    print("first")
    create_one_process = multiprocessing.Process(target=create_test_function,args=("good",))
    create_one_process.daemon = True
    create_one_process.start()
    print("second")
    create_two_process = multiprocessing.Process(target=create_test_function,args=("nice",))
    create_two_process.daemon = False
    create_two_process.start()
    print("third")
'''
output:
           first
           second
           third
           nice
'''

#4、设置daemon一个False一个True
import multiprocessing
import time,datetime

def create_test_function(statement):
    time.sleep(2)
    print(statement)
    
if __name__ == "__main__":
    print("first")
    create_one_process = multiprocessing.Process(target=create_test_function,args=("good",))
    create_one_process.daemon = False
    create_one_process.start()
    print("second")
    create_two_process = multiprocessing.Process(target=create_test_function,args=("nice",))
    create_two_process.daemon = True
    create_two_process.start()
    print("third")
'''
output:
        first
        second
        third
        good
'''    
设置daemon
import multiprocessing
import time,datetime
def create_test_function(statement):
    time.sleep(2)
    print(statement)   
if __name__ == "__main__":
    print("first")
    create_one_process = multiprocessing.Process(target=create_test_function,args=("1",))
    create_one_process.daemon = True
    create_one_process.start()
    create_one_process.join()
    print("second")
    create_two_process = multiprocessing.Process(target=create_test_function,args=("2",))
    create_two_process.daemon = True
    create_two_process.start()
    #create_two_process.join()
    print("third")
'''output:
first
1
second
third
'''

import multiprocessing
import time,datetime
def create_test_function(statement):
    time.sleep(2)
    print(statement)   
if __name__ == "__main__":
    print("first")
    create_one_process = multiprocessing.Process(target=create_test_function,args=("1",))
    create_one_process.daemon = True
    create_one_process.start()
    create_one_process.join()
    print("second")
    create_two_process = multiprocessing.Process(target=create_test_function,args=("2",))
    create_two_process.daemon = True
    create_two_process.start()
    create_two_process.join()
    print("third")
'''output:
first
1
second
2
third
'''
设置join
import multiprocessing
import time,datetime
def create_test_function(statement):
    time.sleep(2)
    print(statement)  
if __name__ == "__main__":
    for i in xrange(4):
        create_one_process = multiprocessing.Process(target=create_test_function,args=(i,))
        create_one_process.daemon = True
        create_one_process.start()
        create_one_process.join()
    print("cheers")

2、Queue

Queue的功能是将每个核或线程的运算结果放在队里中, 等到每个线程或核运行完毕后再从队列中取出结果, 继续加载运算。原因很简单, 多线程调用的函数不能有返回值, 所以使用Queue存储多个线程运算的结果。

import multiprocessing as mp

def job(q):
    res=0
    for i in range(1000):
        res+=i+i**2+i**3
    q.put(res)    #queue

if __name__=='__main__':
    q = mp.Queue()
    p1 = mp.Process(target=job,args=(q,))
    p2 = mp.Process(target=job,args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    res1 = q.get()
    res2 = q.get()
    print(res1+res2)
put和get

3、Pool

进程池就是我们将所要运行的东西,放到池子里,Python会自行解决多进程的问题。 Pool和之前的Process的不同点是丢向Pool的函数有返回值,而Process的没有返回值。

对于需要使用几个甚至十几个进程时,我们使用Process还是比较方便的,但是如果要成百上千个进程,用Process显然太笨了,multiprocessing提供了Pool类,即现在要讲的进程池,能够将众多进程放在一起,设置一个运行进程上限,每次只运行设置的进程数,等有进程结束,再添加新的进程。
Pool(processes =num):设置运行进程数,当一个进程运行完,会添加新的进程进去
apply_async(函数,(参数)):非阻塞,其中参数是tulpe类型,
apply(函数,(参数)):阻塞
close():关闭pool,不能再添加新的任务
terminate():结束运行的进程,不再处理未完成的任务
join():和Process介绍的作用一样, 但要在close或terminate之后使用。

import multiprocessing as mp

def job(x):
    return x*x
def multicore():
    pool = mp.Pool()
    res = pool.map(job, range(10))
    print(res)
    
if __name__ == '__main__':
    multicore()
map
#coding=utf-8
#Pool默认大小是CPU的核数,我们也可以通过在Pool中传入processes参数即可自定义需要的核数量,
import multiprocessing as mp
def job(x):
    return x*x
def multicore():
    pool = mp.Pool(processes=3) # 定义CPU核数量为3
    res = pool.map(job, range(10))
    print(res)
    
if __name__ == '__main__':
    multicore()
Pool
#coding=utf-8
#apply_async()中只能传递一个值,它只会放入一个核进行运算,但是传入值时要注意是可迭代的,所以在传入值后需要加逗号, 同时需要用get()方法获取返回值。
import multiprocessing as mp
def job(x):
    return x*x
def multicore():
    pool = mp.Pool() 
    res = pool.map(job, range(10))
    print(res)
    res = pool.apply_async(job, (2,))
    # 用get获得结果
    print(res.get())
if __name__ == '__main__':
    multicore()
apply_async
#coding=utf-8
#用 apply_async() 输出多个结果 。
import multiprocessing as mp
def job(x):
    return x*x
def multicore():
    pool = mp.Pool() 
    res = pool.map(job, range(10))
    print(res)
    res = pool.apply_async(job, (2,))
    # 用get获得结果
    print(res.get())
    # 迭代器,i=0时apply一次,i=1时apply一次等等
    multi_res = [pool.apply_async(job, (i,)) for i in range(10)]
    # 从迭代器中取出
    print([res.get() for res in multi_res])
if __name__ == '__main__':
    multicore()
apply_async(二)

1、Pool默认调用是CPU的核数,传入processes参数可自定义CPU核数
2、map() 放入迭代参数,返回多个结果
3、apply_async()只能放入一组参数,并返回一个结果,如果想得到map()的效果需要通过迭代

4、共享内存

#我们可以通过使用Value数据存储在一个共享的内存表中。
import multiprocessing as mp
value1 = mp.Value('i', 0) 
value2 = mp.Value('d', 3.14)
#其中d和i参数用来设置数据类型的,d表示一个双精浮点类型,i表示一个带符号的整型。
Value
#在Python的mutiprocessing中,有还有一个Array类,可以和共享内存交互,来实现在进程之间共享数据。

array = mp.Array('i', [1, 2, 3, 4])
#这里的Array和numpy中的不同,它只能是一维的,不能是多维的。同样和Value 一样,需要定义数据形式,否则会报错。
Array
各参数代表的数据类型
| Type code | C Type             | Python Type       | Minimum size in bytes |
| --------- | ------------------ | ----------------- | --------------------- |
| `'b'`     | signed char        | int               | 1                     |
| `'B'`     | unsigned char      | int               | 1                     |
| `'u'`     | Py_UNICODE         | Unicode character | 2                     |
| `'h'`     | signed short       | int               | 2                     |
| `'H'`     | unsigned short     | int               | 2                     |
| `'i'`     | signed int         | int               | 2                     |
| `'I'`     | unsigned int       | int               | 2                     |
| `'l'`     | signed long        | int               | 4                     |
| `'L'`     | unsigned long      | int               | 4                     |
| `'q'`     | signed long long   | int               | 8                     |
| `'Q'`     | unsigned long long | int               | 8                     |
| `'f'`     | float              | float             | 4                     |
| `'d'`     | double             | float             | 8                     |
各参数代表的数据类型

5、进程锁

为了解决不同进程抢共享资源的问题,我们可以用加进程锁来解决。

#coding=utf-8
import multiprocessing as mp
import time
def job(v, num, l):
    l.acquire() # 锁住
    for _ in range(5):
        time.sleep(0.1) 
        v.value += num # 获取共享内存
        print(v.value)
    l.release() # 释放

def multicore():
    l = mp.Lock() # 定义一个进程锁
    v = mp.Value('i', 0) # 定义共享内存
    p1 = mp.Process(target=job, args=(v,1,l)) # 需要将lock传入
    p2 = mp.Process(target=job, args=(v,3,l)) 
    p1.start()
    p2.start()
    p1.join()
    p2.join()

if __name__ == '__main__':
    multicore()
Lock

 ---------------------------------------------------------------------------------------------

并行、并发、同步、异步、阻塞、非阻塞
自己的不确定性理解:

(同步:某个线程调用一直等待系统调用结果返回,才会执行)

(异步:某个线程调用没有等待系统调用结果返回,就直接执行)

(阻塞:)

(非阻塞:)

并行:多个CPU核心,不同的程序就分配给不同的CPU来运行。可以让多个程序同时执行。

并发:单个CPU核心,在一个时间切片里一次只能运行一个程序,如果需要运行多个程序,则串行执行。

同步与阻塞,异步与非阻塞的区别:
  同步与异步是对应的,它们是线程之间的关系,两个线程之间要么是同步的,要么是异步的。
  阻塞与非阻塞是对同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞。
  阻塞是使用同步机制的结果,非阻塞则是使用异步机制的结果。

一、概念

1. 同步:调用时,在没有得到结果之前,该调用就不返回,按照这个定义,绝大多数函数都是同步调用。一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。
最常见的例子就是 SendMessage。
2. 异步:调用者不会立刻得到结果,调用发出后,通过状态(效率低)、通知,或回调函数来通知调用者。PostMessgae。
3. 同步异步的区别:如何通知调用者得到调用结果,同步等待调用完成,异步通过状态、通知,或回调函数。
4. 阻塞:调用结果返回之前,当前线程会被挂起。socket的read/write/recv
5. 同步与阻塞的区别:同步当前线程还是激活的,只是从逻辑上当前函数没有返回而已。
6. 非阻塞:不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
7. 异步与非阻塞的区别:非阻塞是立刻返回调用结果,异步不会立刻返回调用结果,而是通过状态,通知,回调。
8. 异步与阻塞的关系:异步也会调用阻塞的函数,比如用select 函数,当select 返回可读时再去read 一般都不会被阻塞,但是read是一个阻塞的函数。
9. 同步异步和阻塞非阻塞之间的区别:同步异步是如何通知的概念,阻塞和非阻塞是如何执行的概念。
二、 同步/异步与阻塞/非阻塞的组合分析
同步阻塞形式: 等待执行结果是一直等待,执行时线程挂起(未对fd 设置O_NONBLOCK 标志位的read/write 操作)
同步非阻塞形式:等待执行结果是一直等待,执行时函数立即返回(对fd 设置O_NONBLOCK 标志位的read/write 操作)
异步阻塞形式:不是在处理消息时一直等待(通过状态、通知,或回调函数通知主调函数select ),而是在等待消息被触发时被阻塞(线程挂起).如果select 函数,的最后一个timeout 参数为NULL,程序就会停止在select这里。
异步非阻塞形式:在处理消息是不等待,在执行消息是也不等待。

6、上下文和启动方法

根据不同的平台, multiprocessing 支持三种启动进程的方法。这些启动方法有:
spawn
父进程会启动一个全新的 python 解释器进程。 子进程将只继承那些运行进程对象的 run() 方法所必需的资源。 特别地,来自父进程的非必需文件描述符和句柄将不会被继承。 使用此方法启动进程相比使用 fork 或 forkserver 要慢上许多。
可在Unix和Windows上使用。 Windows上的默认设置。

fork
父进程使用 os.fork() 来产生 Python 解释器分叉。子进程在开始时实际上与父进程相同。父进程的所有资源都由子进程继承。请注意,安全分叉多线程进程是棘手的。
只存在于Unix。Unix中的默认值。

forkserver
程序启动并选择* forkserver * 启动方法时,将启动服务器进程。从那时起,每当需要一个新进程时,父进程就会连接到服务器并请求它分叉一个新进程。分叉服务器进程是单线程的,因此使用 os.fork() 是安全的。没有不必要的资源被继承。
可在Unix平台上使用,支持通过Unix管道传递文件描述符。

posted @ 2019-04-22 14:03  Einewhaw  阅读(262)  评论(0编辑  收藏  举报