Python进阶丨进程和线程 —— 多进程

多进程

- 描述

由于Python中全部解释器锁(GIL)的存在,所以Python多线程并不能有效利用CPU多核的性能(相当于单核并发)实现多线程多核并行。

如果想充分地使用多核CPU的资源,需要使用多进程,Python中提供multiprocessing实现。

- multiprocessing

multiprocessing模块就是跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象

语法:

multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={},*,daemon=None)

参数

group —— 始终是None
target —— 是由run()方法调用的可调用的对象,默认None
name —— 进程名称
args —— 目标调用的参数元组
kwargs —— 目标调用的关键字参数字典
daemon —— 是否为守护进程

方法

start(): 启动进程活动,并调用该子进程中的run()
run():进程启动时运行的方法,正是它去调用target指定的函数
is_alive():返回进程是否还活着
join([timeout]):如果可选参数timeout是None(默认值),则该方法将堵塞,直到调用join()方法的进程终止

通俗的讲哪个子进程调用了join方法,主进程就要等该子进程执行完成后才继续往下执行

from multiprocessing import Process
import os

# 子进程要执行的代码
def run_proc(name):
    print('Run child process {} {}...'.format(name, os.getpid()))
    # os.getpid()获取当前进程id

if __name__ == '__main__':
    print('Rarent process {}'.format(os.getpid()))
    p = Process(target=run_proc, args=('test',))
    print('Child process will start')
    p.start()
    p.join()
    print('Child process end')

输出结果

Parent process 14100
Child process will start
Run child process test 14128...
Child process end
- Pool

如果要启动大量的子进程,可以用进程池的方式批量创建子进程

from multiprocessing import Pool

import os
import time
import random

def long_time_task(name):
    print('Run task {} {}...'.format(name, os.getpid()))
    start = time.time()
    time.sleep(random.random()*3)
    end = time.time()
    print('Task {} runs {:.2f} seconds'.format(name, (end-start)))

if __name__ == '__main__':
    print('Parent process {}.'.format(os.getpid()))
    p = Pool(4)
    for i in range(5):
        p.apply_async(long_time_task, args=(i,))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')

输出结果

Parent process 6868.
Waiting for all subprocesses done...
Run task 0 3812...
Run task 1 6952...
Run task 2 11300...
Run task 3 7644...
Task 1 runs 0.33 seconds
Run task 4 6952...
Task 2 runs 0.60 seconds
Task 4 runs 1.73 seconds
Task 0 runs 2.06 seconds
Task 3 runs 2.46 seconds
All subprocesses done.

Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了。

task0,1,2,3是立刻执行的,而task4要等待前面某个task完成后才执行。是因为p = Pool(4),最多同时执行4个进程。

Pool的默认大小是CPU的核数

- 进程间通信

Process之间是需要通信的。Python的multiprocessing模块包装了底层的机制,提供了Queue交换数据

from multiprocessing import Process, Queue
import os
import time
import random


# 写数据进程执行的代码
def write(q):
    print('Process to write:{}'.format(os.getpid()))
    for value in ['A','B','C']:
        print('Put {} to queue...'.format(value))
        q.put(value)
        time.sleep(random.random())

# 读数据进行执行的代码
def read(q):
    print('Process to read:{}'.format(os.getpid()))
    while True:
        value = q.get(True)
        print('Get {} from queue'.format(value))

if __name__ == '__main__':
    # 附近成功创建Queue,并传给各个子进程
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 启动子进程pw, 写入
    pw.start()
    # 启动子进程pr, 读取
    pr.start()
    # 等待pw结束
    pw.join()
    # pr 进程里是死循环,无法等待其结束,只能强制终止
    pr.terminate()

输出结果

Process to write:13548
Put A to queue...
Process to read:8048
Get A from queue
Put B to queue...
Get B from queue
Put C to queue...
Get C from queue
- 知识拓展

并发:在一个时间段,处理多个任务,单核就可以实现并发

并行:在同一时刻,处理多个任务,必须多核才能并行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值