当前位置:首页>python>Python—进程

Python—进程

  • 2026-10-21 13:28:34
Python—进程

编写完毕的代码,在没有运行的时候,称之为程序

正在运行着的代码,就成为进程

进程(process)是正在运行的程序的实例,但一个程序可能会产生多个进程。

进程,除了包含代码以外,还有需要运行的环境等,所以和程序是有区别的。

1.fork()

Python的os模块封装了常见的系统调用,其中就包括fork,可以在Python程序中轻松创建子进程:

import os# 注意,fork函数,只在Unix/Linux/Mac上运行,windows不可以pid = os.fork()if pid == 0:    print('哈哈1')else:    print('哈哈2')

运行结果: 

说明:

  • 程序执行到os.fork()时,操作系统会创建一个新的进程(子进程),然后复制父进程的所有信息到子进程中
  • 然后父进程和子进程都会从fork()函数中得到一个返回值,在子进程中这个值一定是0,而父进程中是子进程的 id号

在Unix/Linux操作系统中,提供了一个fork()系统函数,它非常特殊。

普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。

子进程永远返回0,而父进程返回子进程的ID。

这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。

getpid()、getppid()

import osrpid = os.fork()if rpid<0:    print("fork调用失败。")elif rpid == 0:    print("我是子进程(%s),我的父进程是(%s)"%(os.getpid(),os.getppid()))    x+=1else:    print("我是父进程(%s),我的子进程是(%s)"%(os.getpid(),rpid))print("父子进程都可以执行这里的代码")

运行结果:

我是父进程(19360),我的子进程是(19361)父子进程都可以执行这里的代码我是子进程(19361),我的父进程是(19360)父子进程都可以执行这里的代码

需要注意的是,虽然子进程复制了父进程的代码段和数据段等,

但是一旦子进程开始运行,子进程和父进程就是相互独立的,它们之间不再共享任何数据。

多次fork

父进程、子进程执行顺序没有规律,完全取决于操作系统的调度算法

2.multiprocessing

Python 提供了一个 multiprocessing 模块,利用它,我们可以来编写跨平台的多进程程序,但需要注意的是 multiprocessing 在 Windows 和 Linux 平台的不一致性:一样的代码在 Windows 和 Linux 下运行的结果可能不同。因为 Windows 的进程模型和 Linux 不一样,Windows 下没有 fork。

先来看一个简单的例子,该例子演示了在主进程中启动一个子进程,并等待其结束,代码如下:

import osfrom multiprocessing import Process  # 模块引入 Process# 子进程要执行的代码def child_proc(name):    print 'Run child process %s (%s)...' % (name, os.getpid())if __name__ == '__main__':    print 'Parent process %s.' % os.getpid()    p = Process(target=child_proc, args=('test',))  # target 指定了进程要执行的函数                                                    # args 指定了参数    print 'Process will start.'    p.start()    # start 方法开始执行该子进程    p.join()     # 阻塞子进程以外的所有进程(这里指父进程)    print 'Process end.'

multiprocessing 模块引入了 Process,Process 是一个用于创建进程对象的类,

target:指定了进程要执行的函数,

args:指定了参数。

start 方法:开始执行该子进程,

join 方法:该方法用于阻塞子进程以外的所有进程(这里指父进程),当子进程执行完毕后,父进程才会继续执行,它通常用于进程间的同步。

可以看到,用上面这种方式来创建进程比直接使用 fork 更简单易懂。现在,让我们看下输出结果:

Parent process 7170.Process will start.Run child process test (10075)...Process end.

Process语法结构如下:

Process([group [, target [, name [, args [, kwargs]]]]])

  • target
    :表示这个进程实例所调用对象;
  • args
    :表示调用对象的位置参数元组;
  • kwargs
    :表示调用对象的关键字参数字典;
  • name
    :为当前进程实例的别名;
  • group
    :大多数情况下用不到;

Process类常用方法:

  • is_alive()
    :判断进程实例是否还在执行;
  • join([timeout])
    :是否等待进程实例执行结束,或等待多少秒;
  • start()
    :启动进程实例(创建子进程);
  • run()
    :如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法;
  • terminate()
    :不管任务是否完成,立即终止;

Process类常用属性:

  • name
    :当前进程实例别名,默认为Process-N,N为从1开始递增的整数;
  • pid
    :当前进程实例的PID值;

进程的创建-Process子类

Process语法结构如下:Process([group [, target [, name [, args [, kwargs]]]]])target:表示这个进程实例所调用对象;args:表示调用对象的位置参数元组;kwargs:表示调用对象的关键字参数字典;name:为当前进程实例的别名;group:大多数情况下用不到;Process类常用方法:is_alive():判断进程实例是否还在执行;join([timeout]):是否等待进程实例执行结束,或等待多少秒;start():启动进程实例(创建子进程);run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法;terminate():不管任务是否完成,立即终止;Process类常用属性:name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数;pid:当前进程实例的PID值;进程的创建-Process子类

3.进程池Pool

Python 提供了进程池的方式,让我们批量创建子进程,让我们看一个简单的示例:

import os, timefrom multiprocessing import Pooldef foo(x):    print 'Run task %s (pid:%s)...' % (x, os.getpid())    time.sleep(2)    print 'Task %s result is: %s' % (x, x * x)if __name__ == '__main__':    print 'Parent process %s.' % os.getpid()    p = Pool(4)         # 设置进程数    for i in range(5):        p.apply_async(foo, args=(i,))    # 设置每个进程要执行的函数和参数    print 'Waiting for all subprocesses done...'    p.close()    p.join()    print 'All subprocesses done.'

在上面的代码中,Pool 用于生成进程池,对 Pool 对象调用 apply_async 方法可以使每个进程异步执行任务,也就说不用等上一个任务执行完才执行下一个任务,

close 方法用于关闭进程池,确保没有新的进程加入,

join 方法会等待所有子进程执行完毕。

看看执行结果:

Parent process 7170.Run task 1 (pid:10320)...Run task 0 (pid:10319)...Run task 3 (pid:10322)...Run task 2 (pid:10321)...Waiting for all subprocesses done...Task 1 result is: 1Task 0 result is: 0Run task 4 (pid:10320)...Task 3 result is: 9Task 2 result is: 4Task 4 result is: 16All subprocesses done.

4.进程间通信

进程间的通信可以通过管道(Pipe),队列(Queue)等多种方式来实现。

Python 的 multiprocessing 模块封装了底层的实现机制,让我们可以很容易地实现进程间的通信。

下面以队列(Queue)为例,在父进程中创建两个子进程,

一个往队列写数据,一个从对列读数据

小结

  • 进程是正在运行的程序的实例。
  • 由于每个进程都有各自的内存空间,数据栈等,所以只能使用进程间通讯(Inter-Process Communication, IPC),而不能直接共享信息。
  • Python 的 multiprocessing 模块封装了底层的实现机制,让我们可以更简单地编写多进程程序。

最新文章

随机文章