进程收尾线程初识
数据共享
from multiprocessing import Manager
把所有实现了数据共享的比较便捷的类都重新又封装了一遍,并且在原有的multiprocessing基础上增加了新的机制list、dict
机制:支持的数据类型非常有限
list、dict都不是数据安全的,需要自己加锁来保证数据安全
1 from multiprocessing import Manager,Process,Lock 2 def work(d,lock): 3 with lock: 4 d['count'] -= 1 5 6 if __name__ == '__main__': 7 lock = Lock() 8 with Manager() as m: # m = Manager() 9 dic = m.dict({'count':100}) 10 p_lst = [] 11 for i in range(10): 12 p = Process(target=work, args=(dic, lock)) 13 p_lst.append(p) 14 p.start() 15 for p in p_lst: 16 p.join() 17 print(dic) 18 #{'count': 90}
with ......
一大段语句
dis模块
python的上下文管理
在执行一大段语句之前,自动做某个操作 open
在执行一大段语句之后,自动做某个操作 close
面向对象的魔术方法
1 import os 2 from multiprocessing import Pool 3 def func(i): 4 print('第一个任务', os.getpid()) 5 return '*'*i 6 7 def call_back(res): #回调函数 8 print('回调函数:', os.getpid()) 9 print('res--->', res) 10 11 if __name__ == '__main__': 12 p = Pool() 13 print('主进程', os.getpid()) 14 p.apply_async(func, args=(1,), callback=call_back) 15 p.close() 16 p.join()
func执行完毕之后执行callback函数
func的返回值会作为callback的参数
回调函数是在主进程中实现的
应用场景:子进程有大量运算要做,回调函数等待结果做简单处理
1 url_lst = [ 2 'http://www.baidu.com', 3 'http://www.sohu.com', 4 'http://www.sogou.com', 5 'http://www.4399.com', 6 'http://www.cnblogs.com', 7 ] 8 import re 9 from urllib.request import urlopen 10 from multiprocessing import Pool 11 12 def get_url(url): 13 response = urlopen(url) 14 ret = re.search('www\.(.*?)\.com', url) 15 print('%s finished' % ret.group(1)) 16 return ret.group(1),response.read() 17 18 def call(content): 19 url,con = content 20 with open(url+'.html', 'wb')as f: 21 f.write(con) 22 if __name__ == '__main__': 23 p = Pool() 24 for url in url_lst: 25 p.apply_async(get_url,args=(url,),callback=call) 26 p.close() 27 p.join()
线程理论基础
进程是计算机中最小的资源分配单位,进程对于操作系统来说还具有一定的负担
创建一个进程,操作系统分配的资源大约有:代码,数据,文件等
为什么要有线程
线程是轻量级的概念,他没有属于自己的进程资源,一条线程只负责执行代码,没有自己独立的代码、数据以及文件
线程是计算机中能被CPU调用的最小的单位,当前大部分计算机中的CPU都是执行的线程中的代码
线程与进程之间的关系:每一个进程中都至少有一条线程在工作
线程的特点:
同一个进程中的所有线程的资源是共享的
轻量级, 没有自己的资源
进程与线程之间的区别:
占用的资源、、调度的效率、、资源是否共享
线程的并行问题
线程可以并行:java、c++,c#等
在cpython中,一个进程中的多个线程是不可以并行的
原因是:Cpython解释器内部有一把全局解释器锁GIL,所以线程不能充分利用多核,同一时刻同一进程中的线程只有一个能被cpu执行
GIL锁确实是限制了你程序的效率,但目前可以帮助你提高线程之间切换的效率
如果是想写高计算型的就要多进程或者换一个解释器
threading 模块
1 import os 2 from threading import Thread 3 def func(i): 4 print('子线程:', i, os.getpid()) 5 6 print('主线程', os.getpid()) 7 for i in range(10): 8 t = Thread(target=func, args=(i,)) 9 t.start()
1 import os 2 from threading import Thread 3 from multiprocessing import Process 4 import time 5 def func(i): 6 print('子:', os.getpid()) 7 8 if __name__ == '__main__': 9 start = time.time() 10 t_lst = [] 11 for i in range(100): 12 t = Thread(target=func, args=(i,)) 13 t.start() 14 t_lst.append(t) 15 for t in t_lst: 16 t.join() 17 end = time.time()-start 18 19 start = time.time() 20 t_lst = [] 21 for i in range(100): 22 p = Process(target=func, args=(i,)) 23 p.start() 24 t_lst.append(p) 25 for p in t_lst: 26 p.join() 27 end2 = time.time()-start 28 print(end, end2) 29 #0.0279843807220459 13.582834720611572
1 from threading import Thread 2 num = 100 3 def func(): 4 global num 5 num -= 1 #每个线程都-1 6 7 t_lst = [] 8 for i in range(100): 9 t = Thread(target=func) #创建一百个线程 10 t.start() 11 t_lst.append(t) 12 for t in t_lst: 13 t.join() 14 print(num) #0
Thread 类的其他用法
Thread实例对象的方法 # isAlive(): 返回线程是否活动的。 # getName(): 返回线程名。 # setName(): 设置线程名。 threading模块提供的一些方法: # threading.currentThread(): 返回当前的线程变量。 # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
1 from threading import currentThread,Thread 2 def func(): 3 time.sleep(2) 4 5 t = Thread(target=func) 6 t.start() 7 print(t.is_alive()) #True(判断线程是否活着) 8 print(t.getName()) #Tread-1 9 t.setName('tt') 10 print(t.getName()) #tt(改名字) 11 12 def func(): 13 print('子线程:', currentThread().ident) 14 time.sleep(2) 15 print('主线程:',currentThread().ident) 16 t = Thread(target=func) 17 t.start() 18 #currentThread().ident返回线程的pid 19 20 from threading import enumerate 21 def func(): 22 print('子进程:', currentThread().ident) 23 time.sleep(2) 24 25 print('主进程:', currentThread().ident) 26 for i in range(10): 27 t = Thread(target=func) 28 t.start() 29 print(len(enumerate())) 30 #enumerate()返回一个包含正在运行的线程的list,len(list) 31 32 from threading import activeCount 33 def func(): 34 print('子线程:', currentThread().ident) 35 time.sleep(2) 36 37 print('主线程:', currentThread().ident) 38 for i in range(10): 39 t = Thread(target=func) 40 t.start() 41 print(activeCount()) 42 #activeCount()返回正在运行的线程数量,与len(threading.enumerate())有相同的结果
守护线程
1 import time 2 from threading import Thread 3 def func(): 4 while True: 5 time.sleep(1) 6 print(123) 7 8 def func2(): 9 print('func2 start') 10 time.sleep(3) 11 print('func2 end') 12 13 t1 = Thread(target=func) 14 t2 = Thread(target=func2) 15 t1.setDaemon(True) 16 t1.start() 17 t2.start() 18 print('主线程代码结束') 19 # func2 start 20 #主线程代码结束 21 #123 22 #123 23 #func2 end
守护线程 是在主线程代码结束之后,再等待子线程执行结束后才结束
主线程结束 就意味着主进程结束
主线程等待所有的线程结束
主线程结束了以后 守护线程会随着主进程的结束而随之结束 不是随着代码的结束而结束
######################################
# 线程
# 线程和进程之间的关系
# 每个进程内都有一个线程
# 线程是不能独立存在的
# 线程和进程之间的区别
# 同一个进程中线程之间的数据是共享的
# 进程之间的数据是隔离的
# 线程是被cpu执行的最小单位
# 操作系统调度
# 进程是计算机中最小的资源分配单位
# python
# GIL锁 全局解释器锁 全局锁
# cpython解释器中的
# 锁线程 :同一时刻同一个进程只会有一个线程访问CPU
# 锁的是线程而不是数据
# 当程序是高IO型的 多线程
# 当程序是高计算(CPU)型的 多进程
# cpu*1 ~ cpu*2
# threading
# Thread
# 守护线程 :主线程结束之后才结束
# socket_server IO多路复用 + 多线程
# 框架 并发的效果 :多线程、协程的概念 flask
# 爬虫 :线程池 协程
# set、dict、list
# 生成器
# 面向对象的进阶 :魔术方法
# 管道
# socket_server的源码

浙公网安备 33010602011771号