进程是正在执行中的应用程序,一个进程包含了该应用程序的全部信息,如加载数据内存空
间、代码、程序数据、对象句柄,执行单元等等,一个应用程序根据其功能的多样性,能够
经过多个进程并发的形式来实现。
计算机中多线程的操做已经能够实现多任务的处理机制了,可是若是涉及到多核 CPU 或者
多个 CPU 的硬件主机,多进程并发编程的实现能比多线程并发机制更加有效的利用和发挥
硬件资源优点。python
名称 | 描述 |
---|---|
Process | 进程类型,用于建立和管理进程 |
Lock | RLock |
Event | 进程事件类型,用于进程同步 |
Condition | 进程条件类型,用于进程同步 |
Queue | 进程队列类型,用于多进程数据共享 |
Manager | 进程管理类型,用于多进程数据共享 |
Listener | Client |
import multiprocessing, time, os def hello_process(): # 打印信息,展现当前进程编号,父进程编号 print("hello my name is process", os.getpid(),os.getppid()) if __name__ == "__main__": # 建立一个进程 proc = multiprocessing.Process(target=hello_process) proc.start() print("hello, i am main:", os.getpid(), os.getppid())
运行程序,查看运行结果
hello ,i am :2456 2772
hello my name is process 13536 2456编程
多进程的面向对象的实现方式相似多线程的操做模式
自定义进程类型,继承系统进程标准类型 multiprocessing.Process
重写父类的 run()方法,在方法中定义执行代码
在使用时建立该自定义进程类型的对象,调用对象的 start()方法启动一个新的进程数组
import multiprocessing, os class MyProcess(multiprocessing.Process): '''自定义一个进程类型''' def run(self): '''重写进程处理方法''' print("hello, my name is process:", os.getpid(), os.getppid()) if __name__ == "__main__": print("hello, my name is main:", os.getpid(), os.getppid()) # 建立并启动一个进程 my_proc = MyProcess() my_proc.start()
多线程的操做模式下咱们的全局变量是多个线程共享的,因此多线程并发模式下对于数据的
修改很是危险,那么多进程模式下数据的处理应该是什么样的呢?
经过两种方式来观察多进程模式下数据的处理网络
参数数据多线程
import multiprocessing, time # 定义全局变量 msg = 3 def chg_numers(): '''定义处理函数,修改全局变量的值''' global msg while msg > 0: msg -= 1 print(multiprocessing.current_process().name, " changed : ", msg) if __name__ == "__main__": # 建立两个进程,同时修改数据 for i in range(2): p = multiprocessing.Process(target=chg_numers) p.start() time.sleep(2) print(multiprocessing.current_process().name, msg)
进程自己就是一个独立运行的程序,多进程意味着当前程序被执行了屡次,每一个进程中全局变量的数据都是互相独立的。并发
import multiprocessing, time def chg_numers(msg): '''定义处理函数,修改全局变量的值''' while msg > 0: msg -= 1 print(multiprocessing.current_process().name, " changed : ", msg) if __name__ == "__main__": # 建立两个进程,同时修改数据 msg = 3 for i in range(2): p = multiprocessing.Process(target=chg_numers, args=(msg,)) p.start() time.sleep(2) print(multiprocessing.current_process().name, msg)
给多进程并发处理函数传递参数的方式,并不能让数据能够被多个进程共享
函数执行并发操做时,每一个进程都会单独拷贝一份当前进程的变量数据进行独立使用而不互
相影响,这也是出现上述代码结果的缘由app
多进程的操做在实际应用中也是很是多的,可是纯底层的代码开发控制并发也是一件很是繁
琐的事情,因此就出现了面向过程多进程并发的优化操做方式:进程池 Pool
经过进程池 Pool 能够快速建立多个进程执行指定函数,完成高并发处理操做async
名称 | 描述 |
---|---|
apply(func, args) | 传递参数 args 并执行函数 func,同时阻塞当前进程直到该函数执行完成,函数 func 只会在进程池中的一个进程中运行 |
close() | Pool 进程池的底层工做机制是向进程池提交任务产生工做进程执行,该方法是主动中止给进程池提交任务,并等待全部提交任务执行完成退出 |
terminate() | 当即结束该进程,当进程池对象被回收时自动调用该方法 |
join() | 等待工做进程退出,再次之间必须调用 close()或者 teminate |
进程池的基本实现函数
import multiprocessing def my_process(): print("hello my name is : ", multiprocessing.current_process().name) if __name__ == "__main__": # 建立一个进程池对象,该进程池能够产生两个处理进程 pool = multiprocessing.Pool(2) # 定义 8 个任务,交给进程池处理 for i in range(8): pool.apply_async(my_process) # 中止提交任务 pool.close() # 独占模式:让主线程等待进程池任务执行完成 pool.join()
能够看到两个进程池产生了两个 工做进程来处理咱们的循环的8个任务高并发
多进程下载
有了进程池,能够简单完成一个多进程任务下载的操做处理
该案例只是模拟多进程处理过程,下载任务数据的代码请参考网络数据爬虫技术
import multiprocessing, time def download(url): print(multiprocessing.current_process().name, "开始下载..") time.sleep(0.5) print(multiprocessing.current_process().name,"下载完成<<") time.sleep(2) return "下载的数据" def savedata(data): print(multiprocessing.current_process().name,"下载的数据") if __name__ == "__main__": # 建立进程池 p = multiprocessing.Pool(5) # 任务下载循环 for i in range(20): p.apply_async(download, args=("http://www.dy2018.com",), callback=savedata) # 中止提交任务 p.close() # 独占 p.join()
执行时,能够看到20个任务被进程池中的5个进程平均分配进行了处理
不一样线程之间的数据通讯,涉及到核心的数据共享问题,主要由PYTHON中提供了内建模块multiprocessing.Manager类型实现
名称 | 描述 |
---|---|
Array | 内置进程间共享数组类型 |
Queue | 内置进程间共享队列类型 |
list() | 内置进程间共享列表类型 |
dict() | 内置进程间共享字典类型 |
Value | 内置进程间共享值类型 |
Barrier | 进程同步类型 |
BoundedSemaphore、Semaphore | 进程信号量类型 |
Lock | RLock |
Event | 进程同步事件类型 |
Condition | 进程同步条件类型 |
多个进程之间的通讯操做,数据的传递在PYTHON中的multiprocessing模块中提供了一个专门用于多进程之间进行数据传递的队列:Queue
名称 | 描述 |
---|---|
put(data [, timeout=None]) | 添加一个数据到队列中 |
put_nowait(data) | 添加一个数据到队列中,非阻塞模式 |
get([timeout=None]) | 从队列中获取一个数据 |
get_nowait() | 从队列中获取一个数据,非阻塞模式 |
full() | 判断队列是否已满 |
empty() | 判断队列是否已空 |
close() | 关闭队列 |
qsize() | 获取队列中的元素数量 |
PYTHON 为了更加友好的多个进程之间的数据通讯操做,提供了一个管道类型专门用于进程之间的协做:mulriprocessing.Pipe
名称 | 描述 |
---|---|
init(duplex=True) | 初始化方法,返回两个数据 conn1,conn2,分别表示管道的两端,默认是双向通讯。若是 duplex=False,conn1 只能接受消息,conn2 只能发送消息 |
send(data) | 发送消息 |
recv() | 接受消息 |