进程定义:
顾名思义,就是正在运行中的程序。是操作系统中分配任务的最小基本单元;
线程定义:
线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己不拥有系统资源;但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
进程和线程的区别
1、进程是操作系统分配任务的基本单位,进程是python中正在运行的程序;当我们打开了1个浏览器时就是开始了一个浏览器进程;
线程是进程中执行任务的基本单元(执行指令集),一个进程中至少有一个线程、当只有一个线程时,称为主线程
2、线程的创建和销毁耗费资源少,进程的创建和销毁耗费资源多;线程很容易创建,进程不容易创建
3、线程的切换速度快,进程慢
4、一个进程中有多个线程时:线程之间可以进行通信;一个进程中有多个子进程时,进程与进程之间不可以相互通信,如果需要通信时,就必须通过一个中间代理实现,Queue、Pipe。
5、多进程可以利用多核cpu,多线程不可以利用多核cpu
6、一个新的线程很容易被创建,一个新的进程创建需要对父进程进行一次克隆
7、多进程的主要目的是充分使用CPU的多核机制,多线程的主要目的是充分利用某一个单核
多进程中,异步执行任务时,CPU内存空间不一致,但是资源数据是主进程中拷贝的;即一个新的进程创建需要对父进程进行一次克隆
进程池
进程池:可以提供指定数量的进程给用户使用,即当有新的请求提交到进程池中时,如果池未满,则会创建一个新的进程用来执行该请求;反之,如果池中的进程数已经达到规定最大值,那么该请求就会等待,只要池中有进程空闲下来,该请求就能得到执行。
作用:
1、当进程数过多时,用于限制同时执行的进程数
2、自动的释放资源,节省内存空间
3、提高效率,节省开辟进程和开辟内存空间的时间及销毁进程的时间
import os
import time
from multiprocessing import Process,Pool
number=100
def func(name):
print(f'子进程的id:{os.getpid()},子进程的名称{name}')
for i in range(3):
global number
number+=1
print(number)
time.sleep(1)
if __name__ == '__main__':
print(f'主进程的id:{os.getpid()}')
p_collects=Pool(5)
p_collects.apply_async(func,args=('process-1',))
p_collects.apply_async(func,args=('process-2',))
p_collects.close() #todo 把当前的进程池关掉,不允许去创建新的进程了
p_collects.join()
print('主线执行完毕')
print(number)
主进程的id:25124
子进程的id:19928,子进程的名称process-1
101
102
103
子进程的id:27500,子进程的名称process-2
101
102
103
主线执行完毕
100
CPU密集型(计算密集型)和IO密集型
CPU密集型(计算密集型):计算圆周率、浮点运算、对视频进行高清解码
IO密集型:涉及到网络、磁盘IO的任务都是IO密集型任务,Web应用
多进程的主要目的是充分使用CPU的多核机制
多线程的主要目的是充分利用某一个单核
全局解释器锁(GIL)
GIL 是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。
保证同一个时刻只有一个线程在运行,所以python多线程并不是并行的,是并发的
对于IO密集型全局解析器锁的存在并不会提高执行的速度
即使存在GIL 在有IO等待操作的程序中,还是多线程快,当然没有资源等待的还是单线程快(科学计算,累加)
有了全局解释器锁(GIL)为什么还需要同步锁?
全局解析器锁(GIL)加在了全局了,没有加到我所想要的位置,加到什么位置不是我们决定的;
包括修改资源的程序和非修改资源的程序,如果出现在修改资源的相关代码上,肯定会出现脏数据。
同步锁:来获取一把互斥锁。互斥锁就是对共享数据进行锁定,保证同一时刻只有一个线程操作数据,是数据级别的锁。
GIL锁是解释器级别的锁,保证同一时刻进程中只有一个线程拿到GIL锁,拥有执行权限。
2个线程执行任务造成数据混乱
import threading
num=0
def work():
global num
for i in range(1000000):
num+=1
print('work',num)
def work1():
global num
for i in range(1000000):
num+=1
print('work1',num)
if __name__ == '__main__':
t1=threading.Thread(target=work)
t2=threading.Thread(target=work1)
t1.start()
t2.start()
t1.join()
t2.join()
print('主线程执行结果',num)
执行结果:明显数据混乱了
work work1 16347351376208
主线程执行结果 1634735
说明:
代码中:num+=1,可以拆解为
num=100
100+1
num=101
同步锁这3行代码执行完毕了才会释放锁
加同步锁(with方法)
from threading import Lock
import threading
num=0
def work():
global num
for i in range(1000000):
with lock:
num+=1
print('work',num)
def work1():
global num
for i in range(1000000):
with lock:
num+=1
print('work1',num)
if __name__ == '__main__':
lock=Lock()
t1=threading.Thread(target=work)
t2=threading.Thread(target=work1)
t1.start()
t2.start()
t1.join()
t2.join()
print('主线程执行结果',num)
work 1845334work1 2000000
主线程执行结果 2000000
加同步锁(acquire方法和release方法)
from threading import Lock
import threading
num=0
def work():
global num
for i in range(1000000):
lock.acquire()
num+=1
lock.release()
print('work',num)
def work1():
global num
for i in range(1000000):
lock.acquire()
num += 1
lock.release()
print('work1',num)
if __name__ == '__main__':
lock=Lock()
t1=threading.Thread(target=work)
t2=threading.Thread(target=work1)
t1.start()
t2.start()
t1.join()
t2.join()
print('主线程执行结果',num)
workwork1 1921583
2000000
主线程执行结果 2000000
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/123179.html