进程(Process)
进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
在当代面向线程设计的计算机结构中,进程是线程的容器。
进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。
引入进程原因
进程特征
结构组成:程序、数据和进程控制块
多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。
进程与程序区别
并行
并行(Parallelism)
并行:指两个或两个以上事件(或线程)在同一时刻发生,是真正意义上的不同事件或线程在同一时刻,在不同CPU资源呢上(多核),同时执行。
特点
并发
并发(Concurrency)
指一个物理CPU(也可以多个物理CPU) 在若干道程序(或线程)之间多路复用,并发性是对有限物理资源强制行使多用户共享以提高效率。
特点
进程调度
进程状态介绍
状态描述
就绪(Ready)状态:当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。
执行/运行(Running)状态:当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。
阻塞(Blocked)状态:正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。
同步/异步
同步(synchronous): 所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。
简言之,要么成功都成功,失败都失败,两个任务的状态可以保持一致。
异步(asynchronous):所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。
Python 进程操作
multiprocess.Process模块
process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。
语法:Process([group [, target [, name [, args [, kwargs]]]]])
由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)。
注意:1. 必须使用关键字方式来指定参数;2. args指定的为传给target函数的位置参数,是一个元祖形式,必须有逗号。
参数介绍:
group:参数未使用,默认值为None。
target:表示调用对象,即子进程要执行的任务。
args:表示调用的位置参数元祖。
kwargs:表示调用对象的字典。如kwargs = {‘name‘:Jack, ‘age‘:18}。
name:子进程名称。
Python_process属性方法介绍
start() 启动进程,调用进程中的run()方法。
run() 进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法 。
terminate() 强制终止进程,不会进行任何清理操作。如果该进程终止前,创建了子进程,那么该子进程在其强制结束后变为僵尸进程;如果该进程还保存了一个锁那么也将不会被释放,进而导致死锁。使用时,要注意。
is_alive() 判断某进程是否存活,存活返回True,否则False。
join([timeout]) 主线程等待子线程终止。timeout为可选择超时时间;需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程 。
daemon 默认值为False,如果设置为True,代表该进程为后台守护进程;当该进程的父进程终止时,该进程也随之终止;并且设置为True后,该进程不能创建子进程,设置该属性必须在start()之前
name 进程名称。
pid 进程pid
exitcode 进程运行时为None,如果为-N,表示被信号N结束了。
authkey 进程身份验证,默认是由os.urandom()随机生成32字符的字符串。这个键的用途是设计涉及网络连接的底层进程间的通信提供安全性,这类连接只有在具有相同身份验证才能成功。
实例:
import os from multiprocessing import Process def Yux(): print(os.getpid(), os.getppid(),88) #20496 20404 88 ;子进程ID 与 父进程ID(此py文件进程ID) print("我是子进程") if __name__=="__main__": print(os.getpid(),os.getppid()) #20404 18172 ;此py文件进程ID 与 pycharm-ID pi = Process(target=Yux) pi.start() #在此程序里开启子进程
实例2(join 方法):
import time from multiprocessing import Process def func_one(name): print("My name is", name) time.sleep(2) print("This is func_one") def func_two(name): print("My name is", name) time.sleep(2) print("This is func_two") if __name__ == ‘__main__‘: p_one = Process(target=func_one, args=("Jack",)) p_two = Process(target=func_two, args=("Mick",)) p_one.start() p_one.join() # 主线程要等待func_one终止,才继续往下走 p_two.start()
实例3(迭代处理进程的执行):
import time from multiprocessing import Process def func_one(name): print("My name is", name) time.sleep(1) def func_two(age): print("My age is", age) time.sleep(5) if __name__ == ‘__main__‘: lst_one = [] lst_two = [] for i in range(5): p_one = Process(target=func_one, args=(‘Mike‘,)) p_two = Process(target=func_two, args=(18,)) p_one.start() p_two.start() lst_two.append(p_two) [p_two.join() for p_two in lst_two] # 父进程要等子进程结束 print("End")
实例4,以继承Process的方式开启进程
import os from multiprocessing import Process class MyProcess(Process): def __init__(self, name): super().__init__() self.name = name def run(self): print("进程为%s,父进程为%s" % (os.getpid(), os.getppid())) print("我的名字是%s" % self.name) if __name__ == ‘__main__‘: p_one = MyProcess(‘张三‘) p_two = MyProcess(‘李四‘) p_thr = MyProcess(‘王五‘) p_one.start() # 自动调用run() p_two.start() p_thr.run() # 直接调用run() p_one.join() p_two.join() # p_thr.join() # 调用run()函数的不可以调用join() print("主进程结束")
注意:调用run()函数的不可以调用join()。
守护进程
守护进程就是会随着主进程的结束而结束的进程,具有以下两个特点:
实例一
import os import time from multiprocessing import Process class MyProcess(Process): def __init__(self, name): super().__init__() self.name = name def run(self): print("进程为%s,父进程为%s" % (os.getpid(), os.getppid())) print("我的名字是%s" % self.name) if __name__ == ‘__main__‘: p_one = MyProcess(‘张三‘) p_two = MyProcess(‘李四‘) p_two.daemon = True # 默认为False,必须在start()之前设置 p_one.start() p_two.start() time.sleep(5) print("主进程结束")
实例二
from multiprocessing import Process import time def func_one(): print("func_one") time.sleep(2) print("End func_one") def func_two(): print("func_two") time.sleep(3) print("End func_two") if __name__ == ‘__main__‘: p_one = Process(target=func_one) p_two = Process(target=func_two) p_one.daemon = True p_one.start() p_two.start() time.sleep(0.1) # 时间太短,导致print("End func_one")无法打印 print("主进程结束")
锁——Lock
通过上面的研究,我们千方百计实现了程序的异步,让多个任务可以同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受我们控制。尽管并发编程让我们能更加充分的利用IO资源,但是也给我们带来了新的问题。
当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题。
使用加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了时间,却保证了数据的安全。
from multiprocessing import Process, Lock import time import json import random def search(): dic = json.load(open(‘db‘)) time.sleep(random.random()) # 模拟读取数据 print("\033[43m剩余票数:%s\033[0m" % dic[‘count‘]) def get(): dic = json.load(open(‘db‘)) time.sleep(random.random()) # 模拟网络延迟 if dic[‘count‘] > 0: dic[‘count‘] -= 1 # 购票成功后减一 time.sleep(1) json.dump(dic, open(‘db‘, ‘w‘)) print("\033[32m购票成功\033[0m") else: print("\033[31m尚无余票\033[0m") def task(lock): lock.acquire() search() get() lock.release() if __name__ == ‘__main__‘: lock = Lock() for i in range(10): p = Process(target=task, args=(lock,)) p.start()
加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改。加锁牺牲了速度,但是却保证了数据的安全。
事件
事件(Event),用于线程间通信,即程序中的其一个线程需要通过判断某个线程的状态来确定自己下一步的操作,就用到了event对象。
事件处理的机制:
全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
clear:将“Flag”设置为False。
set:将“Flag”设置为True。
红绿灯实例:
from multiprocessing import Process, Event import time import random def traffic_light(e): ‘‘‘信号灯函数‘‘‘ while 1: # 红绿灯得一直亮着,要么是红灯要么是绿灯 if e.is_set(): # True,代表绿灯亮,那么此时代表可以过车 time.sleep(5) # 所以在这让灯等5秒钟,这段时间让车过 print(‘\033[31m红灯亮!\n车辆等待中...\033[0m‘) # 绿灯亮了5秒后应该提示到红灯亮 e.clear() # 把is_set设置为False else: time.sleep(5) # 此时代表红灯亮了,此时应该红灯亮5秒,在此等5秒 print(‘\033[32m绿灯亮!\n车辆通过中...\033[0m‘) # 红的亮够5秒后,该绿灯亮了 e.set() # 将is_set设置为True def car_status(num, e): e.wait() # 车等在红绿灯,此时要看是红灯还是绿灯,如果is_set为True就是绿灯,此时可以过车 print(‘第%s辆车过去了‘ % num) if __name__ == ‘__main__‘: event = Event() tra_light = Process(target=traffic_light, args=(event,)) # 信号灯的进程 tra_light.start() for i in range(50): # 描述50辆车的进程 if i % 3 == 0: time.sleep(random.randint(1, 5)) # 车辆出现时间随机 car = Process(target=car_status, args=(i + 1, event,)) car.start()
队列(Queue)
创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。
Queue[maxsize]:maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。底层队列使用管道和锁定实现。另外,还需要运行支持线程以便队列中的数据传输到底层管道中。
队列实例,生产者消费者模型:
from multiprocessing import Process,Queue import time,random def xiao(q,name): while True: q.get() time.sleep(random.randint(2,5)) print("%s 消费了产品" % name) def sheng(q,name): for i in range(10): time.sleep(random.random()) q.put("dog") print("%s 生产了产品" % name) if __name__ == ‘__main__‘: q = Queue() p = Process(target=xiao,args=(q,"光芒")) p.start() p1 = Process(target=sheng,args=(q,"生产者")) p1.start()
————————————————
版权声明:本文为CSDN博主「Akaxian」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_33567641/article/details/81947832
原文:https://www.cnblogs.com/yx3445/p/12658724.html