进程 线程 协程
进程
'''
单核:多个任务:分时间片区执行任务----并发
多核:一个核执行一个任务(任务数和核数一样的情况)---并行,若任务太多,也是并发。
并发:分时间片区执行任务(假同时)
并行:一个核执行一个任务(任务数和核数一样的情况)--真同时
同步:在代码中指的是 依次执行---》单任务
异步:在代码中指单是 同时执行---》多任务
---分析代码时都以并行来看
import multiprocessing
多进程实现:
进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。
它是操作系统动态执行的基本单元,在传统的操作系统中,进程即是
基本的分配单元,也是基本的执行单元。
多进程:正在执行的程序
进程注意点:
例子:-------------------3_体验_边唱边跳.py-------------------
----进程的创建
import multiprocessing
.....
if __name__ == '__main__':
进程对象名 = multiprocessing.Procrss(group = None,target = 任务名,args = (元组传参),kwargs(字典传参))
---创建对象用到的参数:--------6_给进程任务传参.py---------
group:不用传,若要传就传 group = None
target:函数名 target = 函数名
name:进程名,也可以不用设置,因为默认就有 , name = '取的名字'
args:以元组方式给函数传参--->真元组 args = ( ,)
kwargs:以字典形式给函数传参----》真字典 kwargs = { ; , : }
----进程的启动:进程对象名.start(),启动进程
----进程的限制:进程对象.join()----等对象进程执行完,才执行下面的代码
----进程提前结束:进程对象.terminate()----结束进程,需要在主进程中使用,不能在子进程函数中去结束自己
----进程开启守护模式:进程对象.daemon = True,---开启守护模式,即如果设置了这个的进程,在主进程执行完后,和主进程一起结束,不管其执行完与否
----程序强制退出;exit(),对多进程没有用,主进程还是要等子进程执行完后才结束 ----退出程序--------------4_论证主程序的退出.py-------------
----进程注意点:
资源不共享性与互不相联系性:
进程是独立的,当我们新建进程的时候,进程会自己开辟一个内存空间,
然后会把资源拷贝到自己的内存空间里面的去,因此变量的改变不会和其它
进程和主进程的变量产生干扰,因此子进程与子进程之前没有联系不能以打
印的顺序来推出进程执行的顺序,那是他们抢执行接口的结果,他们两者是
没有任何关系。
主进程:
不会等待子进程结束再去完成自己的代码,只发号命令,然后就开始执行自己的任务
主进程会等待所有子进程执行完毕后,再退出
----进程编号和当前进程的获取
multiprocessing.current_process()----获取当前执行任务的进程对象
multiprocessing.current_process().pid----获取当前执行任务的进程对象的编码
os.getpid()----获取当前执行函数的编码
os.getppid()----获取当前执行进程的父进程编码
--子进程之间实现通信:queue
que = multiprocessing.Queue(n) # n表示队列的大小,如果不写就是无限队列
基本语法
que.put('加入的值-任意值')
que.get('取出的值’) # 相当于队列,先进先出
que.put_nowait() # 强行添加;若队列满了,再强行添加,会阻塞,报错
que.get_nowait() # 强行取值;若队列空了,再强行取值,报错
que.full() #返回队列是否是满的
que.empty() #返回队列是否为空
que.qsize() #返回队列的大小 # 此语法在mac上无法使用
注意点:当队列已经满了再往里面加值,会让代码执行产生阻塞,这个时候需要其它队列从离main取出一个值,这个队列后面的代码彩壳正常执行
实际例子--一个进程向队列中传值,一个进程取值另一个:
import multiprocessing
def add(que):
print(multiprocessing.current_process().name)#打印当前执行任务的名字
que.put('a')#向队列中插入值
def take(que):
print(multiprocessing.current_process().name)#打印当前执行任务的名字
print(que.get('a'))#向队列中取出值
if __name__=='__main__':
#创建通信队列
que = multiprocessing.Queue(3)
#创建子进程
p1 = multiprocessing.Process(target = add , args = (que,),name = '向队列中加入值')#传入队列对象
p2 = multiprocessing.Process(target = take, args = (que,),name = '向队列中取出值')#传入队列对象
#队列执行
p1.start()
p2.start()
---代码执行:
向队列中加入值
向队列中取出值
a
--进程池:
在定义的李时候里面会有很多进程,在任务分配的时候,程序根据任务量的多少来决定使用进程的个数与次数,提高执行效率。
--------注意:进程池里面所有的子进程都具有保护性,就是与主进程同生死,因此一定要记住使用join函数
--常用函数
pool.join() #我任务量就这么多了,你们等我弄完。
pool.close() #关闭进程池,这样可以避免后面的代码的执行,受到进程池任务分配完与否等稳定而收到干扰
pool.apply_async(任务名,args,kwargs) # 给池中进程分配任务 【asynschronous】异步
pool.apply() 同步执行,不推荐,因为这样和多进程顺序进行没有区别
实际例子--进程池的异步执行:
#拷贝
'''
import multiprocessing
import time
import os
a = []
def dance():
for i in range(5):
a.append(i)
print('跳舞。。。。',a,multiprocessing.current_process(),multiprocessing.current_process().pid,os.getpid(),os.getppid())
time.sleep(1)
def sing():
for i in range(5):
a.append(i)
print('唱歌。。。。',a,multiprocessing.current_process(),multiprocessing.current_process().pid,os.getpid(),os.getppid())
time.sleep(1)
if __name__ == '__main__':
p1 = multiprocessing.Process(target = dance)
p2 = multiprocessing.Process(target = sing)
p1.start()
p2.start()
import multiprocessing
import os
path = r'/Users/manblue/Downloads/a'
targ = r'/Users/manblue/Downloads/b'
def copy(name):
abs_path = os.path.join(path,name)
abs_targ = os.path.join(targ,name)
with open(abs_path,'rb') as file_r:
with open(abs_targ,'wb') as file_w:
data = file_r.read()
file_w.write(data)
if __name__=="__main__":
pool = multiprocessing.Pool(3)
if not os.path.exists(targ):
os.mkdir(targ)
name_li = os.listdir(path)
for name in name_li:
pool.apply_async(copy,(name,))
pool.close()
pool.join()
'''
拷贝文件---进程池---多层目录
1、运用什么方式更快-----多进程/多线程。------进程池
2、怎样拷贝文件-----对文件内部进行遍历----判断文件/文件夹
-----若文件夹是大文件,还得慢慢拷贝,就是while循环拷贝
3、创建或读取文件
'''
import multiprocessing
import os
def copy(name,path,targ):
print(multiprocessing.current_process().name,"正在光荣对完成使命")
abs_path = os.path.join(path,name)
abs_targ = os.path.join(targ,name)
if os.path.isdir(abs_path):
os.mkdir(abs_targ)
name_li = os.listdir(abs_path)
if name_li:
path = abs_path
targ = abs_targ
for name in name_li:
copy(name,path,targ)
else:
with open(abs_path,'r') as file_r:
with open(abs_targ,'a') as file_w:
while True:
content = file_r.read(6)
if content:
file_w.write(content)
else:
print("拷贝完成")
break
if __name__ == '__main__':
path = r'a'
targ = r'b'
pool = multiprocessing.Pool(3)
if not os.path.exists(targ):
os.mkdir(targ)
name_li = os.listdir(path)
for name in name_li:
pool.apply_async(copy,(name,path,targ))
pool.close()
pool.join()
线程
'''
线程
在一个进程内部,要同时干多件事情,就需要同时运行多个子任务,我们把进程内的这些子任务叫做线程
多线程就是为了同步完成多项任务(在单个程序中同时运行多个线程完成不同的任务和工作),不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率
线程存在于进程当中,同属一个进程下的线程之间共享进程资源
线程的创建:
线程对象名 = threading.Thread(group=None,target = dance, args = (...), kwargs = {...}, name = '...')
线程调用
线程对象.start()
线程的传参
创建线程传参:和进程一摸一样
group = None
target = 任务名
args = () - -真元组
kwargs = {} - -真字典
获取活动线程的列表和获取活动线程的数量:活动线程,即正在执行的线程
活动线程列表:
threading.enumerate()
活动线程数量:
threading.active_count()
主线程会等子线程结束后再结束
设置保护属性(同生共死)
# threading.Tread(...,deamon = True)
# 线程对象.setDeamon(True)
# 线程对象.deamon =True
子线程之间:
资源共享
问题:会出现抢占资源的问题 - --解决问题用互斥锁
互斥锁: 对共享数据进行锁定,保证同一时刻只能有一个线程去操作
可以解决线程互相抢资源的问题,被锁祝的资源只能当前线程用,等用完了解锁在抢
创建:lock_name = threading.Lock()
上锁:lock_name.acquires()
----尽量不要让任务中所有代码都锁住,只能锁住部分数据出错的地方
开锁:lock_name.release()
死锁:一直等待对方释放锁的情景,死锁一旦发生,程序就会停止响应
------------------解决:判断的每一个分支都应该释放锁。
'''
'''
获取活动线程列表 ----- threading.enumerate()
获取活动线程数量------threading.active_count()
'''
import threading
import time
def dance():
for _ in range(5):
print('dance',threading.current_thread().name)
time.sleep(0.5)
def sing():
for _ in range(5):
print('sing',threading.current_thread().name)
time.sleep(0.5)
print(threading.enumerate(),threading.active_count())
t1 = threading.Thread(target = dance,name = 't1')
t2 = threading.Thread(target = sing,name = 't2')
t1.start()
print(threading.enumerate(),threading.active_count())
t2.start()
print(threading.enumerate(),threading.active_count())
协程
'''
协程--微线程
只有在耗时操作的时候需要使用协程(如网络请求 网络下载 网络上传如爬虫/其它iO操作)
是一种用户态的轻量级线程,协程的调度完全由用户控制(进程和线程都是由cpu
内核进行调度)。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,
在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,
可以不加锁的访问全局变量,所以上下文的切换非常快。-------即出现耗时操作时立马进行切换,让cpu不再闲着,高效率利用cpu
表现方式 - -1:
while True:
def 函数1:
......
yield
def 函数2:
......
yield
greenlet
和生成器差不多,只是这个执行时只需执行一个, 对象.switch(), 还是需要人工切换任务,
import greenlet
对象名 = greenlet.greenlet(任务名也就是函数名),一个对象对应一个任务
执行,只需执行一个,另一个会自动跳转 - ----对象名.switch()
gevent
可以自动识别延时操作比如sleep() 网络的请求
IO操作。如果发现在代码中有等待阻塞,那么会自动切到下一个任务中去
import gevent # 导入包
from gevent import monkey # 导入补丁
monkey.patch_all() # 打入补丁
def 函数1(
):
函数体(得有sllep() 网络请求
IO等操作)
def 函数2(
):
函数体(得有sllep() 网络请求
IO等操作)
g1 = gevent.spaen(函数名)
g2 = gevent.spaen(函数名)
g1.join()
g2.join()
'''
from greenlet import greenlet
def homepage():
print("34")
gr2.switch()
print("12")
gr3.switch()
def bbs():
print("84")
gr3.switch()
print("13")
def login():
print("56")
gr1.switch()
print("--end--")
gr1 = greenlet(homepage)
gr2 = greenlet(bbs)
gr3 = greenlet(login)
gr1.switch()
import gevent
import time
from gevent import monkey
monkey.patch_all()
def func_01():
while True:
print('we chat')
gevent.sleep(0.5)
def func_02():
while True:
print('chat 记录')
gevent.sleep(0.5)
g1 = gevent.spawn(func_01)
g2 = gevent.spawn(func_02)
g1.join()
g2.join()