并发与并行
1.并发:
概念:在一段时间内,当cPu面对多个任务时,会将每个任务交替着执行一段时间。
特点:
(1).对于某个瞬间,cPU实际上只在执行一个任务。
(2).cPu通过高频切换不同的任务,让每个任务都能得到推进,仿佛多个任务在"同时执行"。
2.并行
概念:并行依赖于多个cPu,或多核心的cPu,在同一时刻,每个核心都在执行不同的任务。
特点:
(1).对于某个瞬间,每个cPu(或每个核心)都在执行不同的任务。
(2).通过多个CPU(或多个核心)同时工作的方式,让多个任务真的在同时执行。
说明:在现代操作系统中,并发与并行通常都是同时存在的。

同步与异步
1.同步(sync):
概念:发起一个任务之后,需要等该任务完成后,才能继续执行后续任务。
表现:当前执行流会被『阻塞』。
2.异步(async):
概念:发起一个任务之后,不必等该任务完成,就可以继续执行其他任务。备注:虽然不必等待任务完成,但任务完成后,仍然可以通过特定方式获取结果。
表现:当前执行流不会被『阻塞』。
三、注意区分概念:
并发/并行:描述的是任务如何被执行,即:多个任务在执行时,cPU要如何处理。
同步/异步:描述的是任务如何被组织和等待,即:要不要等当前发起的任务执行完,再进行下一个任务。
A注意点:CPU的核心数和执行速度,不会改变任务之间的逻辑依赖关系!
例如:一旦任务1、任务2、任务3之间被设计为同步关系,那么:即便CPU切换任务的速度再快,核心数量再多,也不会在[任务1】没完成的情况下去启动【任务2】
进程与线程
1.进程:
(1).一个正在运行的程序或软件,背后就对应着一个或多个进程。
(2).进程是操作系统进行资源分配的基本单位。
(3).每个进程都有自己独立的一块内存空间。
2.线程:
(1).线程是进程内部的执行单元(一个进程中可以有多个线程)
(2).线程是操作系统进行CPU调度的基本单位。
(3).同一进程内的线程共享进程资源。
主进程 子进程
python
import os
print(os.getpid()) #当前进程的pid
print(os.getppid()) #当前进程的父进程pid
在windows操作系统中,查看:进程名、父进程pid、进程pid的命令如下:
wm1c process get Name,ParentProcessId,ProcessId
使用 Process 创建进程
python
import os
import time
from multiprocessing import Process
#定义一个speak函数,功能是:每隔一秒说话一次(一共说话1e次)
def speak():
for index in range(10):
print(f'我在说话{index},进程pid是:{os.getpid()}')
time.sleep(1)
#定义一个study函数,功能是:每隔一秒学习一次(一共学习15次)
def study():
for index in range(15):
print(f'我在学习{index},进程pid是:{os.getpid()}')
time.sleep(1)
# speak()
# study()
# 注意:一定要写if __name__=='__main__'这个判断,原因如下:
# 1.当创建子进程时,Python并不会把父进程内存里的speak 函数直接交给子进程。
# 2.Python会启动一个全新的Python解释器进程,重新执行当前的 .py 文件(作为模块)
# 3.在执行过程中,重新定义出一个speak函数,交给子进程。
if __name__ == '__main__':
#创建两个Process类的实例对象(进程对象),分别是p1和p2。
# 注意点1:p1和p2 就对应着以后的两个子进程,在创建它们的时候,就要指定好他们要执行的任务。
# 注意点2:此时的p1和p2只是代码层面的两个进程对象,操作系统还没有真的创建p1和p2两个进程。
p1 = Process(target=speak)
p2 = Process(target=study)
#调用进程对象的start方法,会立刻向操作系统申请一个进程,并且会将该进程交由操作系统进行调度
p1.start()
p2.start()
Process参数
python
import os
import time
from multiprocessing import Process, current_process
#定义一个speak函数,功能是:每隔一秒说话一次(一共说话1e次)
def speak(a,b,msg):
for index in range(10):
print(f'{msg}--{a}--{b}--{current_process().name}--我在说话{index},进程pid是:{os.getpid()}')
time.sleep(1)
#定义一个study函数,功能是:每隔一秒学习一次(一共学习15次)
def study():
for index in range(15):
print(f'我在学习{index},进程pid是:{os.getpid()}')
time.sleep(1)
if __name__ == '__main__':
# Process的参数:
# group: 默认值为None(应当始终为None)
# target: 子进程要执行的可调用对象,默认值为None。
# name: 进程名称,默认为None,如果设置为None,Python会自动分配名字。
# args: 给target传的位置参数(元组)
# kwargs: 给target传的关键字参数(字典)
# daemon:标记进程是否为守护进程,取值为布尔值(默认为None,表示从创建方进程继承)
p1 = Process(target=speak,name='说话进程',args=(666,888),kwargs={'msg':'haha'})
p2 = Process(target=study)
p1.start()
p2.start()
锁(Lock)
python
import os
import time
from multiprocessing import Process, Lock,RLock
def speak(lock):
for index in range(10):
# 上锁: 如果锁是空闲的,立刻上锁,继续往下执行;如果锁被别人拿着: 当前进程会阻塞等待(原地等)
lock.acquire()
print(f'我在说话{index}')
# 释放锁: acquire和release必须成对出现,否则会永远卡住(死等)
lock.release()
time.sleep(1)
#定义一个study函数,功能是:每隔一秒学习一次(一共学习15次)
def study(lock):
for index in range(15):
# with lock:会自动完成两件事:
# (1).进入前: 自动执行lock.acquire()上锁
# (2).离开后: 自动执行lock.release()释放锁
# 好处:即便代码块里发生异常,也能保证释放锁,避免"卡死"
# 备注:RLock可以多次上锁
with lock:
print(f'我在学习{index},进程pid是:{os.getpid()}')
time.sleep(1)
if __name__ == '__main__':
# lock=Lock()
lock=RLock()
p1 = Process(target=speak, args=(lock,))
p2 = Process(target=study, args=(lock,))
p1.start()
p2.start()
join方法 | terminate方法
join方法的作用:阻塞当前进程,等 join前面的进程执行完,再继续往下执行。
join(timeout),其中 timeout 是可选参数,表示等多久,单位是秒。
python
import os
import time
from multiprocessing import Process, Lock,RLock
def speak():
for index in range(10):
print(f'我在说话{index}')
time.sleep(1)
def study():
for index in range(15):
print(f'我在学习{index},进程pid是:{os.getpid()}')
time.sleep(1)
if __name__ == '__main__':
p1 = Process(target=speak)
p2 = Process(target=study)
p1.start()
p2.start()
p1.join()#让主进程等 p1进程执行完毕后,主进程再继续执行。
p1.join()#让主进程等 p2进程执行完毕后,主进程再继续执行。
time.sleep(3)
p1.terminate() #强制终止
进程守护
什么是守护进程?
1.一种“依附于主进程存在的子进程”,一旦主进程结束,它就会被自动终止。
2.简言之:主进程一死,守护进程必跟着死。
守护进程的使用场景:
1.后台监控类任务
2.日志/统计/采样类任务
3.辅助型“陪跑任务”
#注意点:
1.守护进程必须是 子进程。
2.主进程结束,守护进程也会随之结束。
3.守护进程中,不允许再创建新的子进程。
4.必须在start 之前,start()之后,不能再设置daemon
python
import os
import time
from multiprocessing import Process
def monitor():
while True:
try:
with open('log.txt','r',encoding='utf-8') as file:
lines=sum(1 for _ in file)
except FileExistsError:
lines=0
print(f'我是守护进程{os.getpid()},log.txt共有{lines}行')
time.sleep(1)
if __name__ =='__main__':
print(f'我是主进程({os.getpid()})中的[第一行]代码')
p1=Process(target=monitor,daemon=True)
p1.start()
#向文件中写入数据
with open('log.txt', 'a',encoding='utf-8') as file1:
for index in range(10):
file1.write(f'尚硅谷{index}\n')
file1.flush()
time.sleep(1)
print('我是最后一行代码')
进程之间不共享变量
进程之间不共享内存,因此也不共享任何变量