1.程序linux
一堆静态的代码文件程序员
2.进程编程
一个正在运行的程序windows
由操做系统操控调用交由cpu运行 ,被cpu运行设计模式
1。管理控制协调计算机中硬件与软件的关系安全
2。操做系统的做用?网络
2.没有操做系统:大家在开发软件多线程
第一层。对硬件(cpu,内存,磁盘)协调,调用并发
第二层 如何调用接口去编程
第一个做用:将一些对硬件操做的复杂丑陋的接口, 变成简单美丽的接口,open函数
第二个做用:多个进程抢占一个(cpu)资源时,操 做系统会将你的执行变得合理有序,雨露均沾(比较 快感觉不到)
阻塞:input read write sleep recv accept sendto recvfrom 。。。
百万级代码 写的系统
最先出现的计算机:算盘
电子类的计算机发展史
第一代计算机1940~1955(手工操做----穿孔卡片)
在大学里出现了机房,想使用计算机必须预定
先链接调配各个硬件,1.5小时,真空管,而后在插上程序调试,效率低
优势:我的独享整个计算机资源
缺点;1.硬件条件插线,耗时
2.全部人串行执行
优势程序员不用亲自对硬件进行插线操控,效率提升
能够进行批量处理代码
缺点:
1.程序员不能肚子使用计算机
2.你的全部程序仍是串行
1.集成电路:把所用的硬件变小,线路板
2.将两套不一样的生产线合并成一个生产线
技术上的更新:多道技术,操做系统的理念
空间上的复用
将一个内存能够同时加载多个进程
时间上的复用
实现将cpu在多个进程之间来回切换,而且保留状态,在切回来还能保持原样
几乎全部的程序都会有io阻塞
同时加载到内存 3个任务,3个进程,每一个进程都有阻塞状况,只要cpu运行一个进程时,遇到阻塞立马会切换,长时间占用cpu也会切换
提高效率,最大限度的使用cpu
若是是一个IO(阻塞)密集型进程,来回切换提高效率
若是在一个计算密集型,耗时来会切换下降效率
第三代计算机 普遍采用必须的保护硬件(程序之间的内存彼此隔离)以后,推进第三代计算机应用而生
每一个人占用计算机的时间有限的
多人(少于10个)共同使用一个计算机主机
第四代计算机:至今
面向字:大型的科学计算机
面向字符:商用计算机
1。管理控制协调计算机中硬件与软件的关系
2。操做系统的做用?
2.没有操做系统:大家在开发软件
第一层。对硬件(cpu,内存,磁盘)协调,调用
第二层 如何调用接口去编程
第一个做用:将一些对硬件操做的复杂丑陋的接口, 变成简单美丽的接口,open函数
第二个做用:多个进程抢占一个(cpu)资源时,操 做系统会将你的执行变得合理有序,雨露均沾(比较 快感觉不到)
空间上的复用
将一个内存能够同时加载多个进程
时间上的复用
实现将cpu在多个进程之间来回切换,而且保留状态,在切回来还能保持原样
当进程遇到IO阻塞,或者长时间运行,操做系统会将此进程刮起,保留状态,会将cpu强行切换到另外一个进程
串行:全部的任务(进程)一个一个完成
并发:一个cpu完成多个任务,在不一样的任务中来回切换,看起来是同时完成的
并行:多个cpu执行多个任务,真正的同时完成
阻塞:cpu遇到io就是阻塞
非阻塞:没有IO叫非阻塞
程序:一堆静态文件
一个正在执行的程序任务,一个进程
一个程序可否同时开启多个进程?能够
一个子进程必须基于主进程
主进程是启动子进程的
一个主进程能够开启多个子进程。
unix:fork建立子进程
uninx(linux,mac):建立一个子进程会完彻底全复制一个主进程全部的资源,初始资源不变。
windows:操做系统调用CreateProcess处理进程的建立
windows:建立一个子进程,会copy主进程全部的资源,可是会改变一些资源
系统是最主进程
运行程序运行到io进行阻塞 程序进入阻塞状态
阻塞结束进入就绪态 须要在就绪态等待开始运行 等程序遇到io阻塞再进行运行
某特破赛肾multiprocesssing模块 用来开启子进程
进程建立的两种方式()开辟须要的时间长
建立子进程须要时间 有时间停滞 会调用
p.start 是一个建立声明copy一份,一个cpu是并发
这个信号操做系统接收到以后,会从内存中开辟一个子进程空间,而后·在将主进程全部数据进行深copy加载到子进程 而后运行子进程
强调:
1.须要使用关键字的方式来指定参数 2.target是指定子进程要执行的任务(函数名), 3.args是函数的位置参数(实参以元组的形式) 4.name是(函数)子进程的名称 5.group参数未使用,值始终未None
1.p.star()启动进程,并调用该子进程的p.run() 2.p.run():进程启动运行的方法,是它去调用target指定的函数,咱们自定义类的类 3.p.terminate():强制终止进程p,不会进行任何清理操做,若是p建立了子进程,该子进程就成了僵尸进程,使用该方法须要特别当心这种状况。若是p还保存了一个锁那么也将不会被释放,进而致使死锁 4.p.is_alive():若是p仍然运行,返回True 5.p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,须要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
1.p.daemon:默认值为False,若是设为True,表明p为后台运行的守护进程,当p的父进程终止时,p也随之终止,而且设定为True后,p不能建立本身的新进程,必须在p.start()以前设置 2.p.name:进程的名称 3.p.pid:进程的pid 4.p.exitcode:进程在运行时为None、若是为–N,表示被信号N结束(了解便可) 5.p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络链接的底层进程间通讯提供安全性,这类链接只有在具备相同的身份验证键时才能成功(了解便可)
第一个方式
from multiprocessing import Process import time def ppt(name): print(f'{name}is running') time.sleep(2) print(f'{name}is gone') if __name__ == '__main__': ppt()pp2()pp3()#串行运行 p=Process(target=ppt,args=('长鑫',))#对应一个target 是对应一个方法 args==是传入的值 p.start()#启动进程 print('===煮开水') time.sleep(3)
第二种方式
第二种#默认的用类run from multiprocessing import Process import time class MYprocess(Process):#process是父类 def __init__(self):#必须调用父类的init实现 super().__init__()#执行父类的init self.name=name def run(self):#必须是run要不会继承父类的run print(f'{self.name}is running') print(f'{self.name}is gone') if __name__ == '__main__': p=MYprocess()#建立一个进程对象(子程序) p2=MYprocess()#建立一个进程对象(子程序) p.start()#时间会有时间延迟#声明开辟一个子进程的空间会把主进程的初始值深copy下来 p.start()#由于会有时间延迟 print('===主')#先走这、、
会引用父类的init 要运行本地的init 要使用父类的super.init()
子类没有用父类的 必须有run
tasklist命令行查看全部进程的pid
进程的pid是进程的惟一标识 运行一次开辟一次
import os print(os.getpid())#每次获取的id都不一样的(子进程)
如何在子进程得到主进程的pid
import os print(os.getppid())#每次获取的id都不一样的(父进程)
子进程的名字会改变子进程深copy过来的主进程的名字 不会改变原有的名字
进程与进程之间是由物理隔离:不能共享内存数据(lsook 队列)
#空间隔离 from multiprocessing import Process import time name=[1,2] def ppt(): name.append(1) print(name) if __name__ == '__main__': # ppt()pp2()pp3()串行运行 p=Process(target=ppt) #对应一个target 是对应一个方法 args==是传入的值 p.start() time.sleep(3) print(f'主{name}')#子程序深copy 会有空间隔离
import是模块后面的属性
join让主进程等待子进程运行结束以后在运行主程序
join就是阻塞 主程序有join就会阻塞等待对应子进程运行完
同时开启 前面执行后面也在执行读秒 join是结束 会阻塞
join from multiprocessing import Process import time def task(sec): print('is,running') time.sleep(sec) print('is gone') if __name__ == '__main__': start_time=time.time() p1=Process(target=task,args=(6,)) p2=Process(target=task,args=(7,)) p3=Process(target=task,args=(8,)) p1.start()#同时执行 p2.start()#同时执行 p3.start()#同时执行 p1.join()#遇到阻塞 等待执行完 end_name = time.time() - start_time print(end_name)### p2.join() end_name = time.time() - start_time print(end_name) p3.join() end_name=time.time()-start_time print(end_name)
from multiprocessing import Process import time import os def task(n): time.sleep(3) print('%s is running' %n,os.getpid(),os.getppid()) if __name__ == '__main__': p1 = Process(target=task,args=(1,),name = '任务1') p1.start() # p1.terminate() # time.sleep(2) # 睡一会,他就将个人子进程杀死了#没有直接杀死。 # print(p1.is_alive()) # False#判断子程序是不是活着的 ------------------------------------- #更名字 # print(p1.name) # 给子进程起名字 # for i in range(3): # p = Process(target=task, args=(1,)) # print(p.name) # 给子进程起名字 代码示例
daemon
from multiprocessing import Process import time class MYprocess(Process): # def __init__(self,name):#必须调用父类的init实现 # super().__init__()# # self.name=name def run(self):#必须是run要不会继承父类的run print(f'{self.name}is running') print(f'{self.name}is gone') if __name__ == '__main__': p=MYprocess() p,daemon=True#要在设置执行子进程以前设置成守护进程 p1.start()#时间会有时间延迟 p.start()#由于会有时间延迟 print('===主')#先走这、、 #主进程结束子进程也结束
子进程守护着守护主进程,只要主进程结束
#主进程代码运行完毕,守护进程就会结束 from multiprocessing import Process from threading import Thread import time def foo(): print(123) time.sleep(1) print("end123") def bar(): print(456) time.sleep(3) print("end456") if __name__ == '__main__':#必需要有--main p1=Process(target=foo) p2=Process(target=bar) p1.daemon=True p1.start() p2.start() # p1.join() # p2.join() print("main-------") #打印该行则主进程代码结束,则守护进程p1应该被终止,可能会有p1任务执行的打印信息123,由于主进程打印main----时,p1也执行了,可是随即被终止 #随着守护的主进程的结束而结束了
僵尸进程
主进程须要等待子进程结束以后,主进程才结束
主程序时刻监测子进程的运行状态,当子进程结束以后,一段时间,将子进程回收
为何主程序不在子进程结束后对其回收
1.主进程与子进程是异步关系,主进程没法立刻捕获子进程何时结束
2.若是子进程结束以后立刻再内存释放资源,主进程就没有办法检测子进程的状态
全部的字节内存结束以后,会立马释放掉文件的操做链接,内存的大部分数据,可是会保留一些内容:进程号,结束时间,运行状态,等待主进程检测,回收
僵尸进程:
当子进程结束以后,在被主进程回收以前,都会进入僵尸进程状态
僵尸进程有无危害?
若是父进程不对僵尸进程进行回收(wait/waitpid),会产生大量的僵尸进程,这样就会占用内存,占用进程pid
孤儿进程:
父进程因为某种缘由,结束了,可是你的子进程还在运行中,这样你的这些子进程就成了孤儿进程,你的父进程若是结束,你的全部的孤儿进程就会被init进程回收,init就变成了他们的主进程
出现僵尸进程如何解决?
父进程产生了大量子进程,子程序结束可是不回收,这样就会造成大量的僵尸进程,解决方式僵尸直接杀死父进程,将全部的僵尸进程变成孤儿进程,由init进行回收
并发是效率优先,需求是顺序优先,
多个进程共抢一个资源,要保证顺序优先,并发是效率优先,需求是顺序优先,串行,是一个一个来
强制顺序优先用join串行强制性排序不合理,为保证公平,应该是先到先得
多个任务共抢同一个资源(数据),若是你想要顺序优先(数据安全),必定要让其串行
牺牲效率保证数据安全
把子程序变成串行
能够把串行变得合理有序,保证公平,先到先得 能够把部分变成串行
一把互斥锁锁不能连续锁 只能锁一次
互斥锁必须成对出现
from multiprocess import Lock lock.acquire() lock.release()
acquire上锁,release开锁
# 三个同事 同时用一个打印机打印内容. # 三个进程模拟三个同事, 输出平台模拟打印机. # 版本一: # from multiprocessing import Process # import time # import random # import os # # def task1(): # print(f'{os.getpid()}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{os.getpid()}打印结束了') # # def task2(): # print(f'{os.getpid()}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{os.getpid()}打印结束了') # # def task3(): # print(f'{os.getpid()}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{os.getpid()}打印结束了') # # if __name__ == '__main__': # # p1 = Process(target=task1) # p2 = Process(target=task2) # p3 = Process(target=task3) # # p1.start() # p2.start() # p3.start() # 如今是全部的进程都并发的抢占打印机, # 并发是以效率优先的,可是目前咱们的需求: 顺序优 先. # 多个进程共强一个资源时, 要保证顺序优先: 串行,一 个一个来. # 版本二: # from multiprocessing import Process # import time # import random # import os # # def task1(p): # print(f'{p}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{p}打印结束了') # # def task2(p): # print(f'{p}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{p}打印结束了') # # def task3(p): # print(f'{p}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{p}打印结束了') # # if __name__ == '__main__': # # p1 = Process(target=task1,args= ('p1',)) # p2 = Process(target=task2,args= ('p2',)) # p3 = Process(target=task3,args= ('p3',)) # # p2.start() # p2.join() # p1.start() # p1.join() # p3.start() # p3.join() # 咱们利用join 解决串行的问题,保证了顺序优先,可是 这个谁先谁后是固定的. # 这样不合理. 你在争抢同一个资源的时候,应该是先到 先得,保证公平. # 版本3: from multiprocessing import Process from multiprocessing import Lock import time import random import os def task1(p,lock): ''' 一把锁不能连续锁两次 lock.acquire() lock.acquire() lock.release() lock.release() ''' lock.acquire() print(f'{p}开始打印了') time.sleep(random.randint(1,3)) print(f'{p}打印结束了') lock.release() def task2(p,lock): lock.acquire() print(f'{p}开始打印了') time.sleep(random.randint(1,3)) print(f'{p}打印结束了') lock.release() def task3(p,lock): lock.acquire() print(f'{p}开始打印了') time.sleep(random.randint(1,3)) print(f'{p}打印结束了') lock.release() if __name__ == '__main__': mutex = Lock() p1 = Process(target=task1,args= ('p1',mutex)) lock与join的区别. 共同点: 均可以把并发变成串行, 保证了顺序. 不一样点: join人为设定顺序,lock让其争抢顺序,保证了公 平性. 3. 进程之间的通讯: 进程在内存级别是隔离的,可是文件在磁盘上, 1. 基于文件通讯. 利用抢票系统讲解. p2 = Process(target=task2,args= ('p2',mutex)) p3 = Process(target=task3,args= ('p3',mutex)) p2.start() p1.start() p3.start()
锁总结,
当不少进程共抢一个资源(数据)时,你要保证顺序(数据的安全必定要串行),
join
咱们利用join 解决串行的问题,保证了顺序优先
锁
会合理的对子进程进程排序根据运行的速度和操做系统的阻塞进行排队 保证公平不强制固定
举例查票
# 版本二: # from multiprocessing import Process # import time # import random # import os # # def task1(p): # print(f'{p}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{p}打印结束了') # # def task2(p): # print(f'{p}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{p}打印结束了') # # def task3(p): # print(f'{p}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{p}打印结束了') # # if __name__ == '__main__': # # p1 = Process(target=task1,args= ('p1',)) # p2 = Process(target=task2,args= ('p2',)) # p3 = Process(target=task3,args= ('p3',)) # # p2.start() # p2.join() # p1.start() # p1.join() # p3.start() # p3.join() # 咱们利用join 解决串行的问题,保证了顺序优先,可是 这个谁先谁后是固定的. # 这样不合理. 你在争抢同一个资源的时候,应该是先到 先得,保证公平.
队列和管道都是将数据存放于内存中
咱们应该尽可能避免使用共享数据,尽量使用消息传递和队列,避免处理复杂的同步和锁问题,并且在进程数目增多时,每每能够得到更好的可获展性。
from multiprocessing import Process,Queue import random import time import os lis=[] def search(mete): time.sleep(random.randint(1,5)) s=mete.get() mete.put(s) print(f'手机尾号{os.getpid()}的用户查看了,还剩余名额{s}') # print(lis) def paid(mete,mete1): time.sleep(random.randint(1,3)) s=mete.get() if int(s)>0: s-=1 mete.put(s) phone=os.getpid() print(f'手机尾号{phone}得到了手机名额剩余{s}') mete1.put(phone) else: # mete1.get() # lis.append(mete1.get()) # print(f'{lis}恭喜以上得到名额') print(f'手机尾号{os.getpid()}没有获得名额') mete.put(s) def task(mete,lis): search(mete) paid(mete,lis) if __name__ == '__main__': mete=Queue() mete1=Queue(10) mete.put(10) lst =[] for i in range(30): p=Process(target=task,args=(mete,mete1))#传入了两个管道 p.start() lst.append(p) for i in lst: i.join() while 1: try: print(mete1.get(block=False)) except Exception: break
队列是串行,谁先拿到谁在前面
put往队列里面放值 get把值取出删除**
先进先出
编程思想,模型,设计模式,理论都是给你一种编程的方法,之后相似的状况,套用便可
生产者:产生数据的
消费者:接受数据作进一步处理的
容器:盆(队列)
队列起到什么做用
容器耦合性过强没有,起到缓冲的做用,平衡生产力与消费力,解耦
from multiprocessing import Process from multiprocessing import Queue import time import random def producer(q,name):#利用for循环 传入 for i in range(1,6):#生成6个 time.sleep(random.randint(1,2)) res=f'{i}号包子' q.put(res)#把6传进去 print(f'生产者{name}生产了{res}') def consumer(q,name): while 1: try: food=q.get(timeout=3) time.sleep(random.randrange(1,4)) print(f'\033[31;0m消费者{name}吃了{food}\033[0m') except Exception: return if __name__ == '__main__': q=Queue() p1=Process(target=producer,args=(q,'孙宇')) p2=Process(target=consumer,args=(q,'海狗')) p1.start() p2.start()
一条流水线的工做流程。
进程:在内存中开启一个进程空间,而后将主进程的全部数据复制一份
而后调用线程去执行代码
运行过程自己叫作线程
同一个线程资源共用 执行是进程的代码
是cpu最小的执行单位
资源单位,一个进程存在至少存在主线程
进程是一个资源单位 是一个独立的资源 有空间隔离
若是想要通讯 须要利用queue
在内存中申请一块空间把代码放进去cpu调用内存空间的代码的过程
运行的过程还会使用进程中的资源
开启一个进程:进程会在内存中开辟一个进程空间,将主进程的资料数据所有复制一份,线程会执行里面的代码
子进程是先运行主进程全部程序
线程先加载主进程里面的代码
线程速度快 并发同时执行两个任务 共用资源
不会复制
涩乳癌的thread
同一进程内的资源数据对于多个线程来讲是共享的
线程里面pid就是一个主进程的pid
from threading import Thread def task(name): print(os.getpid())#主进程的pid if __name__ == '__main__': t1=Thread(target=task,args=('海狗',)) t1.start() print('===主线程')
线程没有pid 主进程开辟子进程比较耗时
并发:一个cpu执行多个任务,看起来像是同时执行多个任务
单个进程开启三个线程,并发的执行任务
开启三个进程并发的执行任务
主进程须要等待线程结束
主线程子线程没有地位之分,可是,一个进程谁在干活?一个主线程在干活,当干完活了。等待其余线程干完活以后,才能结束本进程
线程没有主次之分 两种方式函数和类
不须要main 写了好区分 nnnnnn
''' 基于函数的 ''' from threading import Thread import time def task(name): print(f'{name}is running') time.sleep(1) print(f'{name}is gone') if __name__ == '__main__': t1=Thread(target=task,args=('海狗',)) t1.start() print('===主线程')
#基于类 from threading import Thread import time class func(Thread): def __init__(self,name): super().__init__() self.name=name print(1) def run(self): print(self.name) if __name__ == '__main__':#这句话能够不写 由于线程没有主次之分只是多开一个线程 t1=Thread(target=func,args=('立业',)) t1.start() print('主线程')
1.速度对比(主进程必定在子进程以前)(线程速度快 先执行子线程,在执行主进程)
2.线程里面pid就是一个主进程的pid,线程里面没有pid
3.同一进程内的资源数据对于多个线程来讲是共享的
也可使用进程里面的方法
join是同样 的 都是等待子线程(进程)结束
daemon 守护进程 主线程执行完就结束了
Thread实例对象的方法 # isAlive(): 返回线程是否活动的。 # getName(): 返回线程名。 # setName(): 设置线程名。 threading模块提供的一些方法: # threading.currentThread()同等与current_thread(): 返回当前的线程变量。 # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
from mulitprocessing import Process from threading import Thread # from threading import Thread # from threading import currentThread # from threading import enumerate # from threading import activeCount # import os # import time # # x = 3 # def task(): # # print(currentThread()) # time.sleep(1) # print('666') # print(123) # if __name__ == '__main__': # # t1 = Thread(target=task,name='线程1') # t2 = Thread(target=task,name='线程2') # # name 设置线程名 # t1.start() # t2.start() # # time.sleep(2) # # print(t1.isAlive()) # 判断线程是否活着 # # print(t1.getName()) # 获取线程名 # # t1.setName('子线程-1') # # print(t1.name) # 获取线程名 *** # # # threading方法 # print(current_thread().name) # # print(currentThread()) # 获取当前线程的对象 # # print(enumerate()) # 返回一个列表,包含全部的线程对象 # print(activeCount()) # *** # print(f'===主线程{os.getpid()}')
t.daemon#t.setDaemon(true)
守护线程:若是守护线程的生命周期小于其余线程,则他确定结束
线程速度快 因此主线程结束以前会先执行线程 最后和主线程一块儿结束,
主线程结束条件是 全部子线程结束 由于资源共用 主进程不能结束
from threading import Thread import time def sayhi(name): print('你滚!') time.sleep(2) print('%s say hello' %name) if __name__ == '__main__': t = Thread(target=sayhi,args=('egon',)) # t.setDaemon(True) #必须在t.start()以前设置 t.daemon = True t.start() # 线程的开启速度要跟进程开不少 print('主线程')
为何数据不会持续更新
线程比较快 线程同时操做一个数据 全部开启的一个子线程都会先拿到初始值 进行操做
不加锁
from threading import Thread import time x = 100 def task(): global x temp = x time.sleep(0.1) temp -= 1 x = temp if __name__ == '__main__': t_l1 = [] for i in range(100): t = Thread(target=task) t_l1.append(t) t.start() for i in t_l1: i.join() print(f'主{x}') 不加锁抢占同一个资源的问题
加锁
from threading import Thread from threading import Lock import time x = 100 lock = Lock() def task(): global x lock.acquire() temp = x time.sleep(0.1) temp -= 1 x = temp lock.release() if __name__ == '__main__': t_l1 = [] for i in range(100): t = Thread(target=task) t_l1.append(t) t.start() for i in t_l1: i.join() print(f'主{x}') 同步锁保证数据安全
锁套锁现象
解决死锁现象 会有一个计数器,能够连续加锁加一次计数器加一,计数器变为别人才能抢
from threading import Thread,Lock import time from threading import RLock lock_A=lock_B=RLock() lock_A1=Lock() lock_B1=Lock() class func(Thread): def run(self): self.f1() self.f2() def f1(self): lock_A.acquire() print(f'{self.name}拿到了A锁') lock_B.acquire() print(f'{self.name}拿到了B锁') lock_B.release() lock_B.release() def f2(self): lock_B.acquire() print(f'{self.name}拿到了B锁') lock_A.acquire() print(f'{self.name}拿到了A锁') lock_A.release() lock_B.release() if __name__ == '__main__': for i in range(3): t=func() t.start()
Semaphore信号量
容许多个线程 使用信号量 控制并发次数
创py 空间,开启一个进程
py解释器,py文件都会加载进去
Cpython自带GIL锁
单个进程多线程是并发执行,执行的时候会加锁,执行到io阻塞会挂起,把锁打开,
cpu切换到后面的线程会继续执行,
cpyhon为何加锁?
1.当时都是单核时代,并且cpu价格很是贵
2.若是不加全局锁解释器锁,开发Cpython解释器的程序源就会在源码内部各类主动加锁,解锁,很是麻烦,各类死锁现象等待,他为了省事儿,直接进入解释器时给线程加一个锁
保证解释器Cpython的解释器的数据资源的安全。
单个进程的多线程不能利用多核
Jpython没有锁
pypy没有GIL锁
由于Cpython解释器全部业务逻辑都是围绕单个线程实现的,去掉这个GIL锁,几乎不可能
单个进程的多线程能够并发,可是不能利用多核,不能并行
多个进程能够并发,并行
遇到io阻塞cpu就会切换 空间复用 阻塞结束 GIL锁加上继续执行,执行完释放GIL锁
单个进程的多线程合适,并发
由于并发效果 线程运行一段时间 cpu会进行强行切换
多进程是能够并行(调用多个cpu)的
相同点:都是同种锁,互斥锁
不一样点:
GIL锁全局解释器锁,保护解释器内部的资源数据的安全。
GlL锁上锁,释放锁无需手动操做
本身代码中的互斥锁保护进程中资源的安全
本身定义的互斥锁必须本身手动上锁释放锁
代码验证:
计算密集型
开启多进程合适 多进程(并发,并行)比单进程多线程(并发)快效率高
io密集型
单个进程的多线程的并发
线程不用mian里建立
不管是多线程还剩多进程,若是按照上面的写法
来一我的客户端请求,我就开一个线程(进程),来一个请求开一个线程(进程)请求
应该是这样的:你的计算机容许范围内,开启的线程进程数量越多越好