一、數據共享
from multiprocessing import Manager
把所有實現了數據共享的比較便捷的類都重新又封裝了一遍,并且在原有的multiprocessing基礎上增加了新的機制list、dict
機制:支持的數據類型非常有限
list、dict都不是數據安全的,需要自己加鎖來保證數據安全
from multiprocessing import Manager,Process,Lockdef work(d,lock):with lock:d['count'] -= 1if __name__ == '__main__':lock = Lock()with Manager() as m: # m = Manager()dic = m.dict({'count':100})p_lst = []for i in range(10):p = Process(target=work, args=(dic, lock))p_lst.append(p)p.start()for p in p_lst:p.join()print(dic) #{'count': 90}
with ......一大段語句
dis模塊
python的上下文管理
在執行一大段語句之前,自動做某個操作 open
在執行一大段語句之后,自動做某個操作 close面向對象的魔術方法(雙下杠杠方法)
# 回調函數 in Poolimport os from multiprocessing import Pooldef func(i):print('第一個任務', os.getpid())return '*'*idef call_back(res): #回調函數print('回調函數:', os.getpid())print('res--->', res)if __name__ == '__main__':p = Pool()print('主進程', os.getpid())p.apply_async(func, args=(1,), callback=call_back)p.close()p.join()
func執行完畢之后執行callback函數
func的返回值會作為callback的參數
回調函數是在主進程中實現的
應用場景:子進程有大量運算要做,回調函數等待結果做簡單處理


import re from urllib.request import urlopen from multiprocessing import Poolurl_lst = ['http://www.baidu.com','http://www.sohu.com','http://www.sogou.com','http://www.4399.com','http://www.cnblogs.com', ]def get_url(url):response = urlopen(url)ret = re.search('www\.(.*?)\.com', url)print('%s finished' % ret.group(1))return ret.group(1),response.read()def call(content):url,con = contentwith open(url+'.html', 'wb')as f:f.write(con) if __name__ == '__main__':p = Pool()for url in url_lst:p.apply_async(get_url,args=(url,),callback=call)p.close()p.join()
?
二、線程理論基礎
進程是計算機中最小的資源分配單位,進程對于操作系統來說還具有一定的負擔
創建一個進程,操作系統分配的資源大約有:代碼,數據,文件等
1、為什么要有線程
線程是輕量級的概念,他沒有屬于自己的進程資源,一條線程只負責執行代碼,沒有自己獨立的代碼、數據以及文件
線程是計算機中能被CPU調用的最小的單位,當前大部分計算機中的CPU都是執行的線程中的代碼
線程與進程之間的關系:每一個進程中都至少有一條線程在工作
線程的特點:
同一個進程中的所有線程的資源是共享的
輕量級, 沒有自己的資源
進程與線程之間的區別:
占用的資源、調度的效率、資源是否共享
線程的并行問題:
線程可以并行:java、c++,c#等
在cpython中,一個進程中的多個線程是不可以并行的
原因是:Cpython解釋器內部有一把全局解釋器鎖GIL,所以線程不能充分利用多核,同一時刻同一進程中的線程只有一個能被cpu執行
GIL鎖確實是限制了你程序的效率,但目前可以幫助你提高線程之間切換的效率
如果是想寫高計算型的就要多進程或者換一個解釋器
2、threading 模塊
# 并發import os from threading import Threaddef func(i):print('子線程:', i, os.getpid())print('主線程', os.getpid()) for i in range(10):t = Thread(target=func, args=(i,))t.start()
# 進程和線程的差距import os import time from threading import Thread from multiprocessing import Processdef func(i):print('子:', os.getpid())if __name__ == '__main__':start = time.time()t_lst = []for i in range(100):t = Thread(target=func, args=(i,))t.start()t_lst.append(t)for t in t_lst:t.join()end = time.time()-startstart = time.time()t_lst = []for i in range(100):p = Process(target=func, args=(i,))p.start()t_lst.append(p)for p in t_lst:p.join()end2 = time.time()-startprint(end, end2) #0.0279843807220459 13.582834720611572
# 線程間的數據共享from threading import Threadnum = 100 def func():global numnum -= 1 #每個線程都-1 t_lst = [] for i in range(100):t = Thread(target=func) #創建一百個線程 t.start()t_lst.append(t) for t in t_lst:t.join() print(num) #0?
Thread 類的其他用法
Thread實例對象的方法# isAlive(): 返回線程是否活動的。# getName(): 返回線程名。# setName(): 設置線程名。 threading模塊提供的一些方法:# threading.currentThread(): 返回當前的線程變量。# threading.enumerate(): 返回一個包含正在運行的線程的list。正在運行指線程啟動后、結束前,不包括啟動前和終止后的線程。# threading.activeCount(): 返回正在運行的線程數量,與len(threading.enumerate())有相同的結果。


from threading import currentThread,Thread def func():time.sleep(2)t = Thread(target=func) t.start() print(t.is_alive()) #True(判斷線程是否活著) print(t.getName()) #Tread-1 t.setName('tt') print(t.getName()) #tt(改名字)def func():print('子線程:', currentThread().ident)time.sleep(2) print('主線程:',currentThread().ident) t = Thread(target=func) t.start() #currentThread().ident返回線程的pidfrom threading import enumerate def func():print('子進程:', currentThread().ident)time.sleep(2)print('主進程:', currentThread().ident) for i in range(10):t = Thread(target=func)t.start() print(len(enumerate())) #enumerate()返回一個包含正在運行的線程的list,len(list)from threading import activeCount def func():print('子線程:', currentThread().ident)time.sleep(2)print('主線程:', currentThread().ident) for i in range(10):t = Thread(target=func)t.start() print(activeCount()) #activeCount()返回正在運行的線程數量,與len(threading.enumerate())有相同的結果
3、守護線程
import time from threading import Threaddef func():while True:time.sleep(1)print(123)def func2():print('func2 start')time.sleep(3)print('func2 end')t1 = Thread(target=func) t2 = Thread(target=func2) t1.setDaemon(True) t1.start() t2.start() print('主線程代碼結束') # func2 start #主線程代碼結束 #123 #123 #func2 end
?
守護線程 是在主線程代碼結束之后,再等待子線程執行結束后才結束
主線程結束? 就意味著主進程結束
主線程等待所有的線程結束
主線程結束了以后? 守護線程會隨著主進程的結束而隨之結束? 不是隨著代碼的結束而結束
??
#################################################################################
線程
線程和進程之間的關系
每個進程內都有一個線程
線程是不能獨立存在的
線程和進程之間的區別
同一個進程中線程之間的數據是共享的
進程之間的數據是隔離的
線程是被cpu執行的最小單位
操作系統調度
進程是計算機中最小的資源分配單位
python
GIL鎖 全局解釋器鎖 全局鎖
cpython解釋器中的
鎖線程 :同一時刻同一個進程只會有一個線程訪問CPU
鎖的是線程而不是數據
當程序是高IO型的 多線程
當程序是高計算(CPU)型的 多進程
cpu*1 ~ cpu*2
threading
Thread
守護線程 :主線程結束之后才結束
socket_server IO多路復用 + 多線程
框架 并發的效果 :多線程、協程的概念 flask
爬蟲 :線程池 協程
set、dict、list
生成器
面向對象的進階 :魔術方法
管道
socket_server的源碼