1 什么是进程?
进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
狭义定义:进程是正在运行的程序的实例。
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
进程是一个内核级的实体,进程结构的所有成分都在内核空间中,一个用户程序不能直接访问这些数据。
进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域,数据区域和堆栈。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储活动过程调用的指令和本地变量。
进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。
进程是操作系统中最基本、最重要的概念。是多任务系统出现后,为了刻画系统内部出现的动态情况,描述系统内部个程序的活动规律引进的一个概念,所有多任务设计操作系统都建立在进程的基础上。
2 进程的特征
动态性:进程的实质是程序在多任务系统中的一次执行过程,进程是动态产生,动态消亡的。
并发性:任何进程都可以同其他进程一起并发执行。
独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度执行。
结构特征:进程有程序、数据和进程控制块三部分组成。
多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。
3 进程的状态
创建
就绪
运行
阻塞
结束
进程切换
进程运行状态
tcp
udp
import os #程序执行后,当前程序就是主进程,有一个pid
print (os.getpid()) #打印了一下当前主进程的pid
pid = os.fork() #创建一个子进程,创建后,又两个进程同时运行了。
#进程1:主进程,pid=子进程的pid号
#进程2;新建的子进程,pid = 0--->是fork函数的返回值,不是子进程的进程号。
#pid有2个值,第1个值在主进程的地址空间里面,值是子进程的Pid
#pid有2个值,第2个值在子进程的地址空间里面,值是0,(fork函数的返回值)
#以下所有代码,分别会被主进程和子进程分别执行一次
#主进程:
1)打印当前进程pid(子进程的pid)
2)执行了else,打印else的相关语句:父进程的id和子进程的id
#子进程:
#1)打印当前进程pid(0)
#2)执行了if,打印了相关语句:父进程的id和子进程的id
print (pid) #子进程id和0
if pid == 0:#子进程
print ('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
else:
print ('I (%s) just created a child process (%s).' % (os.getpid(), pid))
多进程能解决的问题:
1 以前是单进程,1个人干活,有并发效果么?没有
2 多进程是多个人干货,有并发效果,能够并行计算和处理。
提升处理的效率和速度,增大并发处理能力。
典型场景:
1 爬虫:多进程/线程
2 统计类工作:多进程/线程
本质:
1 异步处理:任务都是单独的
2 用多进程/多线程并发方式处理异步的任务,可以大大提升速度。
我们的用途
1 多进程/多线程的爬虫
2 压力测试程序
3 测试框架中,增加并发执行测试用例
多进程/多线程的编程模型:
1 声明多进程相关的类:锁、队列、共享变量等(多个进程可以公共访问的对象)
2 实现任务的内容—》编写一个或多个函数。任务的流程或计算的过程等等。
3 生成多个进程/线程,给他们每个进程/线程分别分配执行的任务函数
4 开始执行所有的进程/线程
5 用join等待所有进程任务执行完毕
6 打印一下最终的计算结果
创建进程
multiprocessing模块的Process类
(1)Process类的构造方法:
help(multiprocessing.Process)
init(self, group=None, target=None, name=None, args=(), kwargs={})
(2)参数说明:
group: 进程所属组,基本不用。
target: 表示调用对象,一般为函数。
args: 表示调用对象的位置参数元组。
name: 进程别名。
kwargs: 表示调用对象的字典
import multiprocessing #引入了多进程的包
def do(n) :#任务函数
#获取当前进程的名字
name = multiprocessing.current_process().name
print(name,'starting')#打印了进程的名字
print("worker ", n) #打印了workern的字符串信息
return
if __name__ == '__main__' :
numList = [] #存放进程对象的list
for i in range(5) :#通过for循环生成5个进程
p = multiprocessing.Process(name="光荣之路",target=do, args=(i,))
numList.append(p)
print(numList)
print(p,"start***")
p.start()#启动执行新建进程的任务,进程会调用do函数来执行
print("end")
p.join() #等待当前进程执行完毕后,才会执行主进程后续代码。
print("Process end.")
print(numList)
import multiprocessing #引入了多进程的包
import time
def do(n) :#任务函数
#获取当前进程的名字
name = multiprocessing.current_process().name
print(name,'starting')#打印了进程的名字
time.sleep(2)
print(name, n) #打印了workern的字符串信息
return
if __name__ == '__main__' :
start = time.time()
numList = [] #存放进程对象的list
for i in range(5) :#通过for循环生成5个进程
p = multiprocessing.Process(name="光荣之路",target=do, args=(i,))
numList.append(p)
p.start()#启动执行新建进程的任务,进程会调用do函数来执行
p.join() #等待当前进程执行完毕后,才会执行主进程后续代码。
print("Process end.")
print(numList)
end=time.time()
print("执行耗时:%s" %(end - start))
改成并发效果
import multiprocessing #引入了多进程的包
import time
def do(n) :#任务函数
#获取当前进程的名字
name = multiprocessing.current_process().name
print(name,'starting')#打印了进程的名字
time.sleep(2)
print(name, n) #打印了workern的字符串信息
return
if __name__ == '__main__' :
start = time.time()
numList = [] #存放进程对象的list
for i in range(5) :#通过for循环生成5个进程
p = multiprocessing.Process(name="光荣之路"+str(i),target=do, args=(i,))
numList.append(p)
print(p,"start***")
p.start()#启动执行新建进程的任务,进程会调用do函数来执行
print("end")
#p.join() #等待当前进程执行完毕后,才会执行主进程后续代码。
print("Process end.")
print(numList)
for i in numList: #等待所有进程都执行完毕,如果没有这个for就会先执行下面的语句
i.join() #每个进程都join()一下
print(numList)
end=time.time()
print("执行耗时:%s" %(end - start))
join:等待当前进程的任务执行完毕,才会向下执行。
for执行之后,等于5个进程都执行完毕了,才继续打印numlist
打印的numlist
同步的情况打印stop
<Process(光荣之路, stopped)>
Linux下执行
#!/usr/bin/python
# -*- coding: utf-8 -*-
from multiprocessing import Process
import os
import time
def sleeper(name, seconds): #任务函数
print("Process ID# %s" % (os.getpid()))
print("Parent Process ID# %s" % (os.getppid()))
#仅支持在linux上,一个进程会有父进程和自己的ID,windows上就没有父进程id
print("%s will sleep for %s seconds" % (name, seconds))
time.sleep(seconds)
child_proc = Process(target = sleeper, args = ('bob', 5))
child_proc.start()
print("in parent process after child process start")
print("parent process about to join child process")
child_proc.join()
print("in parent process after child process join" )
print("the parent's parent process: %s" % (os.getppid()))
多进程模板程序
import multiprocessing
import urllib.request
import time
def func1(url) :
response = urllib.request.urlopen(url)
html = response.read()
print(html[0:20])
time.sleep(1)
def func2(url) :
response = urllib.request.urlopen(url)
html = response.read()
print(html[0:30])
time.sleep(1)
if __name__ == '__main__' :
p1 = multiprocessing.Process(target=func1,args=("http://www.sogou.com",),name="gloryroad1")
p2 = multiprocessing.Process(target=func2,args=("http://www.baidu.com",),name="gloryroad2")
p1.start()
p2.start()
p1.join()
p2.join()
time.sleep(1)
print("done!")
进程池:
Pool类中的方法
测试但进程和多进程程序执行的效率
import multiprocessing
import time
def m1(x):#打印个平方值
time.sleep(0.01)
return x * x
if __name__ == '__main__':
#生成了一个进程池,帮你生成进程
#当前机器的cpu核数:multiprocessing.cpu_count()
pool = multiprocessing.Pool(multiprocessing.cpu_count())
i_list = range(1000)
time1=time.time()
pool.map(m1, i_list)
time2=time.time()
print('time elapse:',time2-time1)
time1=time.time()
list(map(m1, i_list))
time2=time.time()
print('time elapse:',time2-time1)
import multiprocessing
import time
def m1(x):#打印个平方值 x-->a的实例
time.sleep(0.01)
return x.x+x.y
class a:
def __init__(self,x,y):
self.x =x
self.y =y
if __name__ == '__main__':
#生成了一个进程池,帮你生成进程
#当前机器的cpu核数:multiprocessing.cpu_count()
pool = multiprocessing.Pool(multiprocessing.cpu_count())
i_list = [a(i,i*10) for i in range(1000)]
time1=time.time()
result = pool.map(m1, i_list)
time2=time.time()
print('time elapse:',time2-time1)
print(result)
创建简单的进程池
from multiprocessing import Pool
import multiprocessing
import time
def f(x):
print(multiprocessing.current_process().name,x)
time.sleep(1)
return x * x
if __name__ == '__main__':
pool = Pool(processes = 4) # start 4 worker processes
result1 = pool.apply_async(f, [10]) # 从进程池里选择一个进程异步执行
result2 = pool.apply_async(f, [11]) # 从进程池里选择一个进程异步执行
result3 = pool.apply_async(f, [12])
result4 = pool.apply_async(f, [13])
result5 = pool.apply_async(f, [14])
print("start:")
print(result1.get(timeout = 2))
print(result2.get(timeout = 2))
print(result3.get(timeout = 2))
print(result4.get(timeout = 2))
print(result5.get(timeout = 2))
print(pool.map(f, range(10))) # prints "[0, 1, 4,..., 81]"
同步进程(Queue)
多进程同步,多进程之间有依赖
from multiprocessing import Process, Queue
#import queue
import time
import random
def offer(queue):
# 入队列
for i in range(5):
time.sleep(random.randint(1,5))
queue.put("Hello World"+str(i)) #想队列里面写了hello world!
if __name__ == '__main__':
# 创建一个队列实例
q = Queue() #在主进程定义的队列 是一个多进程的queue multiprocessing.Queue()
p = Process(target = offer, args = (q,))
p.start()
for i in range(5):
print(q.get()) # 出队列,实现了多进程的同步,get依赖于put成功了
p.join()
#不同进程的变量能跨进程访问吗??不可以
#普通的queue,仅限于主进程访问,传给子进程修改,主进程可以看到修改吗?不可以
#多进程的queue,是所有进程可以访问到的,全局有效。
进程同步(Queue)
from multiprocessing import Process, Queue
import os, time, random
# 写数据进程执行的代码:
def write(q): #向队列中写入字母
for value in ['A', 'B', 'C']:
print('Put %s to queue...' % value)
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码
def read(q):#读,如果不空,就读。
time.sleep(1)#等一秒,先等待队列里面有值
while not q.empty():
# if not q.empty():
print('Get %s from queue.' % q.get(True)) #死等
time.sleep(1) # 目的是等待写队列完成
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程
q = Queue()#声明了一个多进程的queue
pw = Process(target = write, args = (q,)) #一个进程指定写的任务
pr = Process(target = read, args = (q,)) #一个进程指定读的任务
# 启动子进程pw,写入:
pw.start()
# 启动子进程pr,读取:
pr.start()
# 等待pw结束:
pw.join()
pr.join()
print("Done!")
#新的队列:multiprocessing.JoinableQueue()
#先进先出,取出来的对象是个任务对象(一个函数或者一个对象)
#你去执行它之后,你需要告诉这个队列,当前任务执行完了,
#需要调用一下task_done()方法
#如果队列里面的所有任务都被执行了,且每一个任务都调用了task_done()方法
#认为此队列的所有任务被执行完了。
#最后有几个进程,需要给这个队列里面加入几个None,作为任务结束的标志。
import multiprocessing
import time
#继承了Process的类,要求必须覆盖实现原有的run方法。
class Consumer(multiprocessing.Process):#消费者的类
# 派生进程
#2个参数:1--》任务队列 2-->存结果的队列
def __init__(self, task_queue, result_queue):
multiprocessing.Process.__init__(self)
self.task_queue = task_queue #两个队列存到实例变量
self.result_queue = result_queue #方便跨方法使用
# 重写原进程的run方法
def run(self):
proc_name = self.name #声明了进程的名字 父类multiprocessing.Process属性
while True:#死循环,从队列中抢任务
next_task = self.task_queue.get()#从任务队列取Task实例,Task类的实例2*3=6
if next_task is None:#如果遇到None,跳出死循环
# Poison pill means shutdown
print(('%s: Exiting' % proc_name))
self.task_queue.task_done()#任务完成要调用task_done()
break #当前进程结束
print(('%s: %s' % (proc_name, next_task)))
answer = next_task() # __call__()执行任务
self.task_queue.task_done()#任务执行完了,调用task_done()
self.result_queue.put(answer)#把计算结果放到结果队列中
return
class Task(object): #进程执行的任务:返回了一个表达式的字符串,类似2*3=6
def __init__(self, a, b):
self.a = a
self.b = b
def __call__(self): t=Task(2,2) t()调用__call__
time.sleep(0.1) # pretend to take some time to do the work
return '%s * %s = %s' % (self.a, self.b, self.a * self.b) #2*2=4
def __str__(self):
return '%s * %s' % (self.a, self.b)
if __name__ == '__main__':
# 新建了一个任务队列
tasks = multiprocessing.JoinableQueue()
#新建了一个存任务结果的跨进程队列
results = multiprocessing.Queue()
# Start consumers
#计算了当前cpu的核数
num_consumers = multiprocessing.cpu_count()
#打印有几个消费者,cpu有几个核,就有几个消费者。
print(('Creating %d consumers' % num_consumers))
# 创建cup核数量数量个的子进程,一个实例代表一个进程。
consumers = [ Consumer(tasks, results) for i in range(num_consumers) ]
# 依次启动子进程
for w in consumers:
w.start() #默认调用Consumer.run()
# Enqueue jobs
num_jobs = 10
for i in range(num_jobs):
tasks.put(Task(i, i)) #加任务 Task实例
# 毒丸:有几个进程,放几个None
#进程执行的是run方法,里面有死循环,只遇到None才会跳出死循环结束任务
for i in range(num_consumers):
tasks.put(None)
# 等待所有的任务都被执行完
#一共14个任务
tasks.join() #所有任务都被get一次后,且都调用task_done()后,才会继续执行后面的代码
# 从结果队列中打印任务的执行结果。
while num_jobs:
result = results.get()
print ('Result: %s' %result)
num_jobs -= 1