多进程笔记:

2018-06-01  本文已影响0人  97833632c0c7

### 在Python中多进程的创建方式对比:

1. 在Python中,可以通过`os.fork()`创建子进程,但是这种方式只能在`linux`和`unix`以及`mac`下面使用,不能跨平台,所以一般不推荐使用这种方式。

2. 使用`multiprocessing`模块也可以创建多进程,并且这种方式在写起来更加简单,并且支持跨平台。所以一般推荐使用`multiprocessing`的方式来写多进程的代码。

### `multiprocessing`的基本用法:

`multiprocessing`这个模块下面有一个`Process`的类。使用这个类可以创建一个多进程,使用方式如下:

```python

from multiprocessing import Process

import time

def zhiliao():

    print('zhiliao process')

if __name__ == '__main__':

    # 开启一个子进程

    p = Process(target=zhiliao)

    p.start()

    while True:

        print('main process')

        time.sleep(1)

```

需要注意一点的是,如果在`windows`操作系统下,所有和进程创建相关的代码都必须放在`__name__=='__main__'`下面,否则会报错。

### 获取进程号:

1. 通过`os.getpid()`可以获取到当前这个进程的id。

2. 通过`os.getppid()`可以获取到当前这个进程的父进程的id。

### 父进程会等待所有子进程执行完毕后在退出:

如果在父进程中执行完所有代码后,还有子进程在执行,那么父进程会等待子进程执行完所有代码后再退出。

### `join`方法:

`join`方法可以让你的主进程阻塞,知道这个子进程执行完毕以后才会执行主进程后面的代码。

```python

def zhiliao():

    for x in range(5):

        print('子进程:%s' % x)

        time.sleep(1)

if __name__ == '__main__':

    p = Process(target=zhiliao)

    p.start()

    print('主进程')

    # join方法的时候,就相当于主进程会阻塞在这个地方

    # 直到这个子进程执行完毕以后才会执行父进程后的代码

    p.join(3)

    print('所有子进程都执行完毕')

```

### 使用类的方式创建子进程:

1. 使用`Process`作为父类,重新自定义一个类。

2. 在自定义的类中,重写父类的`run`方法,这个是必须的。其他方法,就按照你平时如何写就可以了。

3. 使用自定义的进程类创建子进程的时候,不需要传`target`参数。

```python

class MyProcess(Process):

    def run(self):

        print('子进程的id:%s' % os.getpid())

        print('父进程的id:%s' % os.getppid())

        for x in range(5):

            print('子进程:%s' % x)

if __name__ == '__main__':

    p = MyProcess()

    p.start()

    print('父进程的id:%s' % os.getpid())

    print('子进程开始了')

    p.join()

    print('子进程执行完毕')

```

### 进程池:

1. `multiprocessing`中的`Pool`可以实现一个容器,来管理子进程。

2. 使用进程池有什么好处:进程池可以控制同一时刻,最多只能有多少个进程在运行。

3. 主进程不会等待进程池中的子进程都执行完毕以后再退出。而是如果父进程代码执行完毕以后,就会将整个程序都退出,所以我们在写进程池的时候,应该使用`pool.join()`来保证进程池中所有的子进程都能够执行完成。

4. `apply_async`相当于是并联的方式执行(同一时刻可以执行多个任务)。`apply`相当于是串联的方式执行(同一时刻只能执行一个任务,并且只能等待前面的任务执行完后才能执行后面的任务)。

```python

from multiprocessing import Process,Pool

import os

import time

def worker(num):

    for x in range(5):

        print('num:%s,pid:%s' % (num, os.getpid()))

        time.sleep(1)

if __name__ == '__main__':

    # 这个池子中同一时刻最多只能有3个进程

    pool = Pool(3)

    for x in range(10):

        pool.apply_async(worker,(x,))

    # 关闭进程池,不能再添加新进程了

    pool.close()

    # 主进程把子进程添加到进程池中后,不会等待进程池中其他的子进程都执行完毕后再退出,

    # 而是当主进程的代码执行完毕后会立刻退出,因此如果这个地方没有join,那么子进程

    # 将得不到执行

    pool.join()

```

### 进程间数据不共享:

在程序中创建了子进程,子进程会完全copy一份主进程的环境,包括变量、函数、类等。

所以在子进程中使用变量、函数等的时候,其实是使用的是子进程中的那一份。跟主进程没有任何关系。

### `Queue`消息队列:

1. Queue(n):初始化一个消息队列,并指定这个队列中最多能够容纳多少条消息。

2. put(obj,[block[,timeout]]):推入一条消息到这个队列中。默认是阻塞的,也就是说如果这个消息队列中已经满了,那么会会一直等待,将这个消息添加到消息队列中。timeout可以指定这个阻塞最长的时间,如果超过这个时间还是满的,就会抛出异常。

3. put_nowait() :非阻塞的推入一条消息,如果这个队列已经满了,那么会立马抛出异常。其实这个方法等价于`put(block=False)`。

4. qsize():获取这个消息队列消息的数量。

5. full():判断这个消息队列是满否了。

6. empty():判断这个消息队列是否空了。

7. get([block[,timeout]]):获取队列中的一条消息,然后将其从队列中移除,block默认为True。如果设置block为False,那么如果没值,会立马抛出异常。timeout指定如果多久没有获取到值后会抛出异常。他获取值的方式是以先进先出的方式获取的。不要被队列两个字误解了。

### 使用`Queue`做进程间通信:

1. 给`Process`进程做通信:直接使用`Queue`的对象作为进程的参数就可以了。

2. 给`Pool`进程做通信,应该使用`multiprocessing.Manager().Queue()`对象来做通信,这个对象的使用方法跟`multiprocessing.Queue()`是一样的。

上一篇下一篇

猜你喜欢

热点阅读