python之多进程

2019-02-16  本文已影响0人  ivan_cq

实例一:
一个简单的多进程实例,要创建进程,需要motiproceing模块。用法和创建线程的差不多。这个程序,实现了创建5个进程,然后每个进程再创建了一个线程。

import multiprocessing
import time
import threading
def f(name):
    time.sleep(2)
    print("hello",name)
    t=threading.Thread(target=thread_run,)
    t.start()

def thread_run():
    print(threading.get_ident())

if __name__ == '__main__':
    for i in range(5):
        p=multiprocessing.Process(target=f,args=('bob %s'%i,))
        p.start()



F:\anaconda\python.exe F:/web/s14/进程、线程/noke.py
hello bob 3
hello bob 0
3820
1992
hello bob 1
3516
hello bob 2
1256
hello bob 4
3744

实例二:
类似于上面的程序,只不过实现了打印当前进程的父进程号和当前进程号,然后在当前进程下创建了子进程,然后打印子进程的父进程号,再打印该子进程号,会得出:每一个子进程都是由父进程启动的

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()


F:\anaconda\python.exe F:/web/s14/进程、线程/noke.py
main process line
module name: __main__
parent process: 1268
process id: 2108



function f
module name: __mp_main__
parent process: 2108
process id: 4040



hello bob

实例三:进程间数据共享的第一种方法:队列
下面这个程序,通过队列,实现了线程间数据共享,注意:这个队列只是普通的队列,没有进行任何封装
queue,线程间的queue是实现线程间生产者消费者模型的,但是只能在当前程序的线程里访问

import queue
import threading


def f(q):
    q.put([42, None, 'hello'])


if __name__ == '__main__':
    q = queue.Queue()
    p = threading.Thread(target=f, args=(q,))
    p.start()
    print(q.get())
    p.join()

下面这个程序,并没有使用正常的queue。使用了封装后的queue
原理:相当于克隆了一个queue。因为在父进程创建子进程的时候放进去queue, 通过一个中间内存,pickle一下序列化一下,再反序列化一下。只是实现了数据的传递

from multiprocessing import Process, Queue
import queue  #不能是线程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()

实例四:进程间数据共享的第二种方法:管道

from multiprocessing import Process, Pipe


def f(conn):
    conn.send([42, None, 'hello'])
    conn.send([42, None, 'hello2'])
    conn.send([42, None, 'hello3'])
    conn.close()


if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    print(parent_conn.recv())
    print(parent_conn.recv())
    print(parent_conn.recv())
    p.join()


F:\anaconda\python.exe F:/web/s14/进程、线程/noke.py
[42, None, 'hello']
[42, None, 'hello2']
[42, None, 'hello3']

实例五:
刚才只是两个进程间数据的传递
那么,如何向在多线程一样同时修改数据呢?
使用manager,注意:不需要加锁,manager默认加锁了,共享数据的原理和queue原理一样

from multiprocessing import Process, Manager
import os

def f(d, l):
    d[os.getpid()]=os.getpid()
    l.append(os.getpid())
    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)

实例六:进程同步:加锁的目的,控制打印顺序(对屏幕进行加锁)
进程里面为什么需要锁?
虽然每个进程都是独立的,但是对于屏幕来说,屏幕不是共享的,控制打印顺序
在windows里面试不出来,在linux里面可以试出来
存在的意义:就是在屏幕上打印

from multiprocessing import Process, Lock


def f(l, i):
    l.acquire()
    print('hello world', i)
    l.release()
if __name__ == '__main__':
    lock = Lock()
    for num in range(10):
        Process(target=f, args=(lock, num)).start()


F:\anaconda\python.exe F:/web/s14/进程、线程/noke.py
hello world 3
hello world 6
hello world 7
hello world 8
hello world 2
hello world 9
hello world 0
hello world 1
hello world 4
hello world 5

实例七:进程池的使用(生产中常用的
我们启动多进程明显很慢,因为开销特别大,所以我们使用线程池。注意:启动特别多的线程仅仅是cpu上下文切换变多,一般情况,系统只是变慢,而启动特别多的进程,容易把系统搞瘫痪

from multiprocessing import Process, Pool,freeze_support
import time
import os

def Foo(i):
    time.sleep(2)
    print("in process ",os.getpid())
    return i + 100

def Bar(arg):
    print('-->exec done:', arg,os.getpid())


if __name__ == '__main__':      #为了区分是主动执行这个脚本,还是导入的模块  意思就是这样写,手动执行这个脚本,就会执行,而导入不会执行
    print("主进程 pid",os.getpid())
    pool = Pool(3)              #允许进程池里同时放入5个进程,放入进程池里的进程才会运行,其他进程挂起
    for i in range(10):
        pool.apply_async(func=Foo, args=(i,), callback=Bar) #并行 ,callback回调 干完foo才能干bar,干不完foo不干bar。  主进程调用的回调。备份完毕自动向数据库写日志。为什么不在子进程写日志?因为父进程只连一次,而子进程要连10次。
        #pool.apply(func=Foo, args=(i,))     #串行

    print('end')
    pool.close()    #一定要先关闭进程池再join
    pool.join()  # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭,不等进程执行完毕程序直接关闭 先close在join
上一篇 下一篇

猜你喜欢

热点阅读