python进程总结

概述

通常来说,多线程是一个好东西。不过由于Python的GIL的限制,多线程更适合于I/O密集型应用(I/O释放了GIL,可以允许更多的并发),而不是计算密集型应用。对于后一种情况而言,为了实现更好的并行性,你需要使用多进程,以便让CPU的其他内核来执行。

multiprocessing

如果你打算编写多进程的服务程序,Unix/Linux无疑是正确的选择。由于Windows没有fork调用,难道在Windows上无法用Python编写多进程的程序?由于Python是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块就是跨平台版本的多进程模块。multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束:

from multiprocessing import Process
import os

# 子进程要执行的代码
def run_proc(name):
    print('Run child process %s (%s)...' % (name, os.getpid()))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Process(target=run_proc, args=('test',))
    print('Child process will start.')
    p.start()
    p.join()
    print('Child process end.')

执行结果如下:

Parent process 928.
Process will start.
Run child process test (929)...
Process end.

创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。
进程间通信:
multiprocessing支持两种进程间通信的方式:Queues(队列)和Pipes(管道)
Queues示例:

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

Queues是线程和进程安全的。
Pipes示例:

from multiprocessing import Process, Pipe

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

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    print(parent_conn.recv()) # prints "[42, None, 'hello']"
    p.join()

Pipe()返回的两个连接对象代表着管道的两个端,每个连接对象都有send()和recv()方法。
常用的方法:

start() # 启动进程。

join() # 等待子进程结束。

is_alive() # 用于检查子进程是否已经结束。

terminate() # 强制结束进程。

subprocess

很多时候,子进程并不是自身(自己定义的方法/函数),而是一个外部进程(exe可执行程序)。subprocess模块可以让我们非常方便地启动一个子进程,然后控制其输入和输出。
subprocess模块创建子进程有两个方法:run()和Popen(),Popen相比run有更多的参数可以设置,功能更强,但一般当run方法满足不了需求时我们才选Popen,因为run比Popen使用起来更简单一些。
举个检查网络是否已连接的例子,其实就是调用cmd命令行执行ping命令:

import subprocess

result = subprocess.run('ping www.baidu.com', stdout=subprocess.PIPE)
print(result.stdout.decode('gb2312'))

运行结果:

正在 Ping www.a.shifen.com [14.215.177.39] 具有 32 字节的数据:
来自 14.215.177.39 的回复: 字节=32 时间=3ms TTL=51
来自 14.215.177.39 的回复: 字节=32 时间=3ms TTL=51
来自 14.215.177.39 的回复: 字节=32 时间=3ms TTL=51
来自 14.215.177.39 的回复: 字节=32 时间=3ms TTL=51

14.215.177.39 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 3ms,最长 = 3ms,平均 = 3ms

常用的方法:

Popen.poll() # 用于检查子进程是否已经结束。设置并返回returncode属性。

Popen.kill() # 杀死子进程。

Popen.wait() # 等待子进程结束。设置并返回returncode属性。

Popen.pid # 获取子进程的进程ID。

进程优缺点

优点:
多进程模式最大的优点就是稳定性高,因为一个子进程崩溃了,不会影响主进程和其他子进程。(当然主进程挂了所有进程就全挂了,但是Master进程只负责分配任务,挂掉的概率低)。
缺点:
多进程模式的缺点是创建进程、进程间切换开销大。

总结

调用外部程序,使用subprocess;让进程执行自己编写的模块,则使用multiprocessing。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值