01.进程
1.1 什么是进程?
1.进程是资源分配的最小单位( 内存、cpu、网络、io) 2.一个运行起来的程序就是一个进程 什么是程序(程序是我们存储在硬盘里的代码) 硬盘(256G)、内存条(8G) 当我们双击图标,打开程序的时候,实际上就是通过I/O操作(读写),硬盘中的代码读取到内存条里 内存条就是我们所指的资源(程序分配了内存资源,就变成了进程) CPU分时 CPU比你的手速快多了,分时处理每个线程,但是由于太快然你觉得每个线程都是独占cpu cpu是计算,只有时间片到了,获取cpu,线程真正执行 当你想使用 网络、磁盘等资源的时候,需要cpu的调度 3.进程具有独立的内存空间,所以没有办法相互通信
1.2 进程如何通信?
同一程序下进程通信
1、进程queue(父子进程通信)
2、pipe(同一程序下两个进程通信)
3、managers(同一程序下多个进程通信)
Java项目和python项目如何通信
1、RabbitMQ、redis等(不同程序间通信)
1.3 为什么需要进程池?
一次性开启指定数量的进程 如果有十个进程,有一百个任务,一次可以处理多少个(一次性只能处理十个) 防止进程开启数量过多导致服务器压力过大 进程池中有两个方法: 1)apply: 多个进程异步执行,一个一个的执行 2)apply_async: 多个进程同步执行,同时执行多个进程
from multiprocessing import Process,Pool import time,os def foo(i): time.sleep(2) print("in the process",os.getpid()) #打印子进程的pid return i+100 def call(arg): print('-->exec done:',arg,os.getpid()) if __name__ == '__main__': pool = Pool(3) #进程池最多允许5个进程放入进程池 print("主进程pid:",os.getpid()) #打印父进程的pid for i in range(10): #用法1 callback作用是指定只有当Foo运行结束后就执行callback调用的函数,父进程调用的callback函数 pool.apply_async(func=foo, args=(i,),callback=call) #用法2 串行 启动进程不在用Process而是直接用pool.apply() # pool.apply(func=foo, args=(i,)) print('end') pool.close() #关闭pool pool.join() #进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。
1.4 僵尸进程
1)僵尸进程定义
1、僵尸进程产生的原因就是父进程产生子进程后,子进程先于父进程退出
2、但是父进程由于种种原因,并没有处理子进程发送的退出信号,那么这个子进程就会成为僵尸进程。
2)用python写一个僵尸进程
#!/usr/bin/env python #coding=utf8 import os, sys, time #产生子进程 pid = os.fork() if pid == 0: #子进程退出 sys.exit(0) #父进程休息30秒 time.sleep(30) # 先产生一个子进程,子进程退出,父进程休息30秒,那就会产生一个僵尸进程
ps -ef| grep defunct
在linux下查看僵尸进程
[root@linux-node4 ~]# ps -ef| grep defunct root 110401 96083 0 19:11 pts/2 00:00:00 python defunct.py root 110402 110401 0 19:11 pts/2 00:00:00 [python] <defunct> root 110406 96105 0 19:11 pts/3 00:00:00 grep --color=auto defunct
1.5 Python中使用过的进程模块?
1.5.1 multiprocessing
1、multiprocessing是一个使用类似于线程模块的API支持产生进程的包。
2、多处理包提供本地和远程并发,通过使用子进程而不是线程有效地侧向执行全局解释器锁。
3、因此,多处理模块允许程序员充分利用给定机器上的多个处理器。 它可以在Unix和Windows上运行。
4、进程池抓取页面
# -*- coding: utf-8 -*- import requests from multiprocessing import Pool def fetch_request(url): result = requests.get(url) print(result.text) def call(arg): print('-->exec done:',"测试进程池执行后回调功能") url_list = [ 'https://www.baidu.com', 'https://www.google.com/', #google页面会卡住,知道页面超时后这个进程才结束 'http://dig.chouti.com/', #chouti页面内容会直接返回,不会等待Google页面的返回 ] if __name__ == '__main__': pool = Pool(10) # 创建线程池 for url in url_list: #用法1 callback作用是指定只有当Foo运行结束后就执行callback调用的函数,父进程调用的callback函数 pool.apply_async(func=fetch_request, args=(url,),callback=call) print('end') pool.close() #关闭pool pool.join() #进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。
1.5.2 concurrent.futures
1、简介 1、Python标准库为我们提供了threading和multiprocessing模块编写相应的多线程/多进程代码 2、但是当项目达到一定的规模,频繁创建/销毁进程或者线程是非常消耗资源的,这个时候我们就要编写自己的线程池/进程池,以空间换时间。 3、但从Python3.2开始,标准库为我们提供了concurrent.futures模块,它提供了ThreadPoolExecutor和ProcessPoolExecutor两个类, 4、实现了对threading和multiprocessing的进一步抽象,对编写线程池/进程池提供了直接的支持。
2、Executor和Future 1. Executor concurrent.futures模块的基础是Exectuor,Executor是一个抽象类,它不能被直接使用。 但是它提供的两个子类ThreadPoolExecutor和ProcessPoolExecutor却是非常有用 我们可以将相应的tasks直接放入线程池/进程池,不需要维护Queue来操心死锁的问题,线程池/进程池会自动帮我们调度。 2. Future Future你可以把它理解为一个在未来完成的操作,这是异步编程的基础, 传统编程模式下比如我们操作queue.get的时候,在等待返回结果之前会产生阻塞,cpu不能让出来做其他事情 而Future的引入帮助我们在等待的这段时间可以完成其他的操作。
3、concurrent.futures.ProcessPoolExecutor 抓取网页
import requests from concurrent.futures import ProcessPoolExecutor def fetch_request(url): result = requests.get(url) print(result.text) url_list = [ 'https://www.baidu.com', 'https://www.google.com/', #google页面会卡住,知道页面超时后这个进程才结束 'http://dig.chouti.com/', #chouti页面内容会直接返回,不会等待Google页面的返回 ] if __name__ == '__main__': pool = ProcessPoolExecutor(10) # 创建线程池 for url in url_list: pool.submit(fetch_request,url) # 去线程池中获取一个进程,进程去执行fetch_request方法 pool.shutdown(wait = True) # shutdown相当于一个开关,它会读取程序中所设定的进程总数,直至每开启一个进程,它读取设定的总数就会减一,直至为0时便会打印主线程