# 0x01 进程基础

## 进程函数

只有符合下面条件的函数才能被多进程使用:

* 任务必须定义成**普通函数**来提交, **实例方法**, **闭包**, **其他类型的可调用对消**都是不支持并行处理的
* 函数的**参数**和**返回值**必须可兼容与**pickle**编码, 因为进程之间的通信, 需要在解释器之间交换数据时, 进行序列化处理

Python中基础的多进程包为**multiprocessing**.

## Process

**Process**是创建进程的类, 创建对象的方法如下:

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

* group: 无用
* target: 调用函数
* name: 进程名称
* args: 参数
* kwargs: 参数

### 方法

* **start()**: 启动线程
* **join(\[timeout])**: 阻塞
* **is\_alive()**: 进程是否在运行

### 属性

* **pid**: 进程号
* **name**: 进程名称
* **daemon**: 定义是否是守护进程, 定义方法与线程`Thread`相同

### 创建进程

```python
import time
import multiprocessing

def worker(interval):
    n = 5
    while n > 0:
        print("The time is {0}".format(time.ctime()))
        time.sleep(interval)
        n -= 1

p = multiprocessing.Process(target = worker, args = (3,))
p.start()
print("p.pid:", p.pid)
print("p.name:", p.name)
print("p.is_alive:", p.is_alive())
```

输出为:

```
p.pid: 1908
p.name: Process-1
p.is_alive: True
The time is Tue Apr 21 20:55:12 2015
The time is Tue Apr 21 20:55:15 2015
The time is Tue Apr 21 20:55:18 2015
The time is Tue Apr 21 20:55:21 2015
The time is Tue Apr 21 20:55:24 2015
```

### 使用类创建进程

类似于多线程定义类继承`threading.Thread`, 并将需要多进程的方法写在`run()`方法中. 同样, 这种方法不推荐, 扩展性差.

```python
import time
import multiprocessing

class ClockProcess(multiprocessing.Process):
    def __init__(self, interval):
        multiprocessing.Process.__init__(self)
        self.interval = interval

    def run(self):
        n = 5
        while n > 0:
            print("the time is {0}".format(time.ctime()))
            time.sleep(self.interval)
            n -= 1

p = ClockProcess(3)
p.start()
```

## 锁

**Lock**, **RLock**与线程包中的使用方法相同.

## 同步原语

**Event**, **Condition**, **Semaphore**与线程包中的使用方法相同.

## 队列

**Queue**与`queue`包中队列`Queue`使用方法相同, 只是这里是针对于多进程的安全的队列.

## Pipe

管道的作用为**作为两个进程之间的通信**, 一端发送, 另一端接受. 当然也每一端也可以即接受又发送. 原理可见[使用pipe管道使python fork多进程之间通信](http://ju.outofmemory.cn/entry/106041).

创建方法为`multiprocessing.Pipe(duplex=True)`, `duplex`表示管道是否是**全双工模式**. 创建会返回`(conn1, conn2)`形式的端口, `conn1`端口负责发送信息, 使用`conn1.send()`方法, `conn2`端口负责接收消息, 使用`conn2.recv()`方法.

当`recv()`方法没有消息可以接收时, 就会产生阻塞.

```python
import time
import multiprocessing

def proc1(pipe):
    while True:
        for i in xrange(10000):
            print "send: %s" %(i)
            pipe.send(i)
            time.sleep(1)

def proc2(pipe):
    while True:
        print "proc2 rev:", pipe.recv()
        time.sleep(1)

pipe = multiprocessing.Pipe()
p1 = multiprocessing.Process(target=proc1, args=(pipe[0],))
p2 = multiprocessing.Process(target=proc2, args=(pipe[1],))
p1.start()
p2.start()
p1.join()
p2.join()
```

## 参考资料

[Python多进程编程](http://python.jobbole.com/82045/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://kerasnoone.gitbook.io/garnet/gong-cheng-zhan/python/bing-fa/duo-jin-cheng/0x01-jin-cheng-ji-chu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
