Python 学习笔记: 多进程

多进程

1 , windows 平台上开启多进程, 使用multiprocessing 时, 要注意主进程的文件中需要使用

  if __name__ == '__main__' : 语句

  

import socket
from multiprocessing import Process

def serv(conn):
    while True:
        conn.send('你好'.encode('utf-8'))
        msg = conn.recv(1024).decode('utf-8')
        print(msg)
        if msg == 'bye':
            break
        info = input('>>>').encode('utf-8')
        conn.send(info)
    conn.close()


if __name__ == '__main__':
    sk = socket.socket()
    sk.bind(('127.0.0.1', 8080))
    sk.listen()
    while True:
        conn,addr = sk.accept()
        p = Process(target=serv, args=(conn,))
        p.start()
    sk.close()

2 利用“锁”来控制数据的安全, 买票程序示例:

from multiprocessing import Process
from multiprocessing import Lock
import time
import json

def show(i):
    with open('ticket.txt','r') as f:
        dic = json.load(f)
    time.sleep(0.1)
    if dic['tickets'] > 0:
        print('用户No. %d 查询到票有%d张'%(i,dic['tickets']))
    else:
        print('用户No. %d 查询到无票' %i)


def buy_ticket(i,lock):
    lock.acquire()  #取得锁
    with open('ticket.txt', 'r') as f:
        dic = json.load(f)
    time.sleep(0.1)
    if dic['tickets'] >0:
        dic['tickets'] -=1
        print('%d 买到票'%i)
    else:
        print('%d没有买到票'%i)
    with open('ticket.txt','w') as f:
        json.dump(dic,f)
    time.sleep(0.1)
    lock.release()   #归还锁


if __name__ == '__main__':
    for i in range(10):
        p = Process(target=show,args=(i,))
        p.start()
    time.sleep(1)
    lock = Lock()
    p_list=[]
    for i in range(10):
        p = Process(target=buy_ticket,args=(i,lock))
        p.start()
        p_list.append(p)
#等待所有子进程执行完
    for i in p_list:
        i.join()

票的文件ticket.txt

{"tickets": 2}

10个人去抢2张票:

执行结果:(买到票的人是不确定的)

用户No. 2 查询到票有2张
用户No. 3 查询到票有2张
用户No. 0 查询到票有2张
用户No. 1 查询到票有2张
用户No. 5 查询到票有2张
用户No. 6 查询到票有2张
用户No. 7 查询到票有2张
用户No. 4 查询到票有2张
用户No. 9 查询到票有2张
1 买到票
用户No. 8 查询到票有2张
0 买到票
2没有买到票
4没有买到票
7没有买到票
6没有买到票
3没有买到票
9没有买到票
8没有买到票
5没有买到票

3 事件。 Event 类, 红绿灯课题举例, 车辆通过红绿灯。

from multiprocessing import Process,Event
import time
import random


def cars(i, e):
    if not e.is_set():
        print('\033[31m汽车%i等待\033[0m'%i)
        e.wait()
    print('\033[32m汽车%i通过\033[0m'%i)


def light(e):
    while True:
        if e.is_set():
            e.clear()
            print('\033[31m红灯亮了 \033[0m\n')
        else:
            e.set()
            print('\033[32m绿灯亮了\033[0m\n')
        time.sleep(3)


if __name__ == '__main__':
    e = Event()
    traffic = Process(target=light, args=(e,))
    traffic.start()
    for i in range(20):
        car = Process(target=cars, args=(i, e))
        time.sleep(random.random())
        car.start()

本例子中, e.wait() 根据e.is_set() 的值决定是否阻塞。 True 时不阻塞, False时阻塞。

 知识点:

from multiprocessing import Event

e = Event()
print(e.is_set())  # 缺省是 False , 阻塞
print('hello')
e.set()           # 设置为 True  , 非阻塞

print(e.is_set())
e.wait()
e.clear()           # 设置为 False , 阻塞
print(e.is_set())   # False , 阻塞
e.wait()
print('world')

4 通过队列实现进程间通信

 

from multiprocessing import Process,Queue

def produce(q):
    q.put('hello')

def consume(q):
    print(q.get())


if __name__ =='__main__':
    q = Queue()
    p = Process(target=produce,args=(q,))
    p.start()

    c = Process(target=consume,args=(q,))
    c.start()

 5 生产者与消费者例子

from multiprocessing import Process
from multiprocessing import JoinableQueue
import time

def procedure(q, name ,product):
    for i in range(20):
        info = '%s 生产了 第 %d个 %s'%(name,i,product)
        print(info)
        q.put('第%i个--%s'%(i,product))
        time.sleep(0.1)
    q.join()


def consume(q,name):
    while True:
        print('%s 消费了 %s'%(name,q.get()))
        time.sleep(0.1)
        q.task_done()



if __name__ =='__main__':
    q = JoinableQueue()

    p1 = Process(target=procedure,args=(q, 'Jinboss','包子'))
    p2 = Process(target=procedure,args=(q, 'Alex','馒头'))
    p1.start()
    p2.start()

    c1 = Process(target=consume, args=(q,'消费者1'))
    # c2 = Process(target=consume,args=(q,'消费者2'))
    c1.daemon = True
    # c2.daemon = True
    c1.start()
    # c2.start()
    p1.join()
    p2.join()

 

6 pipe 管道

from multiprocessing import Pipe, Process

def func(conn1,conn2):
    conn1.close()
    while True:
        try:
            print(conn2.recv())
        except EOFError:
            conn2.close()
            break


if __name__ == '__main__':
    conn1,conn2 = Pipe()
    p1 = Process(target=func, args=(conn1,conn2))
    p1.start()
    conn2.close()
    for i in range(10):
        conn1.send('吃了么')
    conn1.close()

 7 进程池 Pool

from multiprocessing import Pool,Process
import time

def fun(n):
    for i in range(10):
        print(n+i)


if __name__ == '__main__':
    start = time.time()
    pool = Pool(5)
    pool.map(fun,range(100))
    t1 = time.time() - start

    # p_list = []
    # start = time.time()
    # for i in range(100):
    #     p = Process(target=fun, args=(i,))
    #     p_list.append(p)
    #     p.start()
    #
    # for i in p_list:
    #     i.join()
    #
    # t2 = time.time() - start

    print(t1)

进程池的异步提交任务方式:

import os
import time
import random
from multiprocessing import Pool


def func(n):
    print('%s begin ...%s'%(n, os.getpid()))
    time.sleep(random.randint(1,3))
    print('%s end %s'%(n, os.getpid()))


if __name__ == '__main__':
    pool = Pool(5)
    for i in range(10):
        pool.apply_async(func, args=(i,))
    pool.close()
    pool.join()

pool.close() 指进程池不再接收新任务了。

pool.join() 指感知进程池中执行任务的结束。 

 

输出如下: (注意观察进程的开启, 及进程ID始终只有5个进程)

0 begin ...11800
1 begin ...11520
2 begin ...11016
3 begin ...9188
4 begin ...5864
0 end 11800
5 begin ...11800
3 end 9188
6 begin ...9188
1 end 11520
7 begin ...11520
5 end 11800
8 begin ...11800
2 end 11016
9 begin ...11016
6 end 9188
4 end 5864
7 end 11520
9 end 11016
8 end 11800

Process finished with exit code 0

 

8 回调函数

from multiprocessing import Pool
import os


def func1(n):
    print('in func1 %s'%os.getpid())
    return n*n


def func2(m):
    print('in func2 %s'%os.getpid())
    print(m*m)


if __name__ =='__main__':
    p = Pool(5)
    print('main process %s'%os.getpid())
    p.apply_async(func1, args=(10,), callback=func2)
    p.close()
    p.join()

执行结果:回调函数是在主进程中执行的。

main process 272
in func1 12716
in func2 272
10000

 

posted @ 2018-11-26 10:01  程序猿🌽  阅读(144)  评论(0编辑  收藏  举报