线程与进程 之进程

多进程multirocessing

有效的绕过了全局解释器锁(GIL)!!  可以使用真正的多核.

写法跟多线程一毛一样。

from multiprocessing import Process
import time


def f(name):
    time.sleep(2)
    print('hello', name)


if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()

 创建一个新的进程的开销远比线程 大的多的多的多。。。。

from multiprocessing import Process
import os
 
def info(title):
    print(title)
    print('module name:', __name__)
    print('parent process:', os.getppid())
    print('process id:', os.getpid())
    print("\n\n")
 
def f(name):
    info('\033[31;1mfunction f\033[0m')
    print('hello', name)
 
if __name__ == '__main__':
    info('\033[32;1mmain process line\033[0m')
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()

os.getppid()  获取父进程的PID号

os.getpid() 获取当前进程PID号

进程间通信

实现了双方数据的传递,并没有实现数据的共享,并同时修改一份数据.

Queue(队列)

不同的进程间内存是不共享的,要想实现两个进程间的数据交换.

可以用队列的方法

A进程给队列中放,B进程去队列中取

from multiprocessing import Process, Queue
 
def f(q):
    q.put([42, None, 'hello'])
 
if __name__ == '__main__':
    q = Queue()
    p = Process(target=f, args=(q,))
    p.start()
    print(q.get())    # prints "[42, None, 'hello']"
    p.join()

这里要注意的是  :

  1.先声明一个q 为队列。

  2.在声明一个p为子进程

  3.因为是多进程的通信通过的是队列,所以需要把 队列中的数据,传递给p这个进程,p这个进程才可以访问 

  4.进程的内存是独立的, 线程的内存是共享的。

Pipe(管道)

from multiprocessing import Process,Pipe

#管道
def f(conn):
    conn.send([42,None,'父亲'])
    conn.send([43,None,'word'])
    print('from parent',conn.recv())
    conn.close()


if __name__ == '__main__':
    parent_conn,child_conn = Pipe()       #管道 一个头一个尾  就好比 一个父亲 一个儿子
    p = Process(target=f,args=(child_conn,))  #定义是用来接受子请求
    p2 = Process(target=f, args=(child_conn,))
    p.start()
    p2.start()
    print(parent_conn.recv())     #打印 父去接受子的请求
    parent_conn.send('hellow 儿子')
    parent_conn.send('hellow 儿2子')
    p.join()
    p2.join()

剖析:

  1.Pipe() 这里产生了2个进程 一个为 父进程parent_conn,一个为子进程child_conn

  2.send为发,recv为接受

  3.创建2个进程,并把子进程传递给这个函数,这个函数就相当于打印出子进程.

  3.父进程进程可以send多次。。子进程只能recv 接受一次。。

Managers

可以实现进程直接数据的交互修改

实际上:进程之间的数据是没有办法直接修改的,不会像线程那样真正修改同一份数据。

那进程之间修改同一份数据,是主进程把这份数据先copy 或者socket,或者内存映射的方法,把一块内存给共享出来。 这些方法 给另外一个A进程,A进程改完后,在返回给主进程.然后主进程在把数据copy给C进程,D进程.

所以开销是非常大,  这种的进程之间数据共享修改,涉及到进程间数据的来回copy。非常耗资源....

from multiprocessing import Process, Manager
 
def f(d, l):
    d[1] = '1'
    d['2'] = 2
    d[0.25] = None
    l.append(1)
    print(l)
 
if __name__ == '__main__':
    with Manager() as manager:
        d = manager.dict()
 
        l = manager.list(range(5))
        p_list = []
        for i in range(10):
            p = Process(target=f, args=(d, l))
            p.start()
            p_list.append(p)
        for res in p_list:
            res.join()
 
        print(d)
        print(l)

阿。。。。用是这么用。但是还是不会。。。

进程同步

from multiprocessing import Process, Lock


def f(l, i):
    l.acquire()
    try:
        print('hello world', i)
    finally:
        l.release()


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

    for num in range(100):
        Process(target=f, args=(lock, num)).start()

这个东东。就是用来保证屏幕输出正常。。。。应该是2个进程 公用一个屏幕

#这里用到了进程锁。。。。  保证子进程 输出一致

进程池

 进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止.

进程中 有两个方法:

#导入multiprocessing 中的Pool方法

#apply   阻塞的

#apply_async  非阻塞的

#close  关闭pool,使其不再接受其他新的任务

#join() 主进程阻塞,等待子进程的退出,join方法要在close后使用

from  multiprocessing import Process, Pool,Lock
import time

def f(i):
    print('hello word %s' %i)
    time.sleep(1)
    return i
def callback(data):      #回执,相当于 子进程执行完毕后。告诉主进程.  这里callback还可以干很多事,因为这里设置的是把结果都返回给这里了。。所以可以把结果写入日志中
    print('exec done---->',data)

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

    pool = Pool(processes=5)  #设置线程池,有5个进程
    for num in range(100):
        pool.apply_async(func=f,args=(num,),callback=callback)

    pool.close()  #一定要close()   。告诉主进程说,进程池已经添加完毕,可以关闭了
    pool.join()  #进程池中进程执行完毕后在关闭。如果取消,那么程序直接就关闭了

 

posted @ 2016-12-13 19:52  所有的梦想都画在墙上  阅读(198)  评论(0)    收藏  举报