內容轉載自網絡、非原創!此處僅僅收集整理一下方便學習!
```
python 併發和線程
併發和線程
基本概念 - 並行、併發
"並行、 parallel"
互不干擾的在同一時刻作多件事;
如、同一時刻、同時有多輛車在多條車道上跑、即同時發生的概念.python
"併發、 concurrency"
同時作某些事、可是強調同一時段作多件事.
如、同一路口、發生了車輛要同時經過路面的事件.windows
"隊列、 緩衝區"
相似排隊、是一種自然解決併發的辦法.排隊區域就是緩衝區.
```
```
解決併發:
【 "食堂打飯模型", 中午12點,你們都涌向食堂,就是併發.人不少就是高併發.】緩存
一、隊列, 緩衝區:
隊列: 即排隊.
緩衝區: 排成的隊列.
優先隊列: 若是有男生隊伍和女生隊伍,女生隊伍優先打飯,就是優先隊列.服務器
二、爭搶:
鎖機制: 爭搶打飯,有人搶到,該窗口在某一時刻就只能爲這我的服務,鎖定窗口,即鎖機制.
爭搶也是一種高併發解決方案,可是有可能有人很長時間搶不到,因此不推薦.網絡
三、預處理:
統計你們愛吃的菜品,最愛吃的80%熱門菜提早作好,20%冷門菜現作,這樣即便有人鎖定窗口,也能很快釋放.
這是一種提早加載用戶須要的數據的思路,預處理思想,緩存經常使用.數據結構
四、並行:
開多個打飯窗口,同時提供服務.
IT平常能夠經過購買更多服務器,或多開線程,進程實現並行處理,解決併發問題.
這是一種水平擴展的思路.
注: 若是線程在單CPU上處理,就不是並行了.併發
五、提速:
經過提升單個窗口的打飯速度,也是解決併發的方式.
IT方面提升單個CPU性能,或單個服務器安裝更多的CPU.
這是一種垂直擴展的思想.ide
六、消息中間件:
如上地地鐵站的九曲迴腸的走廊,緩衝人流.
常見消息中間件: RabbitMQ, ActiveMQ(Apache), RocketMQ(阿里Apache), kafka(Apache)等.
```
```
進程和線程
a) 在實現了線程的操做系統中,線程是操做系統可以運算調度的最小單位.
b) 線程被包含在進程中,是進程的實際運做單位.
c) 一個程序的執行實例就是一個進程.函數
進程(Process)是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操做系統結構的基礎.
進程和程序的關係: 進程是線程的容器.高併發
Linux進程有父進程和子進程之分,windows的進程是平等關係.
線程有時稱爲輕量級進程,一個標準的線程由線程ID,當前指令指針,寄存器集合和堆棧組成.
當運行一個程序時,OS會建立一個進程。它會使用系統資源(CPU、內存和磁盤空間)和OS內核中的數據結構(文件、網絡鏈接、用量統計等)。
進程之間是互相隔離的,即一個進程既沒法訪問其餘進程的內容,也沒法操做其餘進程。
操做系統會跟蹤全部正在運行的進程,給每一個進程一小段運行時間,而後切換到其餘進程,這樣既能夠作到公平又能夠響應用戶操做。
能夠在圖形界面中查看進程狀態,在在Windows上可使用任務管理器。也能夠本身編寫程序來獲取進程信息。
```
```
# 獲取正在運行的python解釋器的進程號和當前工做目錄,及用戶ID、用戶組ID
import os
os.getpid()
os.getuid()
os.getcwd()
os.getgid()
```
```
對線程、線程的理解:
進程是獨立的王國,進程間不能隨便共享數據.
線程是省份,同一進程內的線程能夠共享進程的資源,每個線程有本身獨立的堆棧.
線程的狀態:
就緒(Ready): 線程一旦運行,就在等待被調度.
運行(Running): 線程正在運行.
阻塞(Blocked): 線程等待外部事件發生而沒法運行,如I/O操做.
終止(Terminated): 線程完成或退出,或被取消.
```
```
python中的進程和線程: 進程會啓動一個解釋器進程,線程共享一個解釋器進程.
python的線程開發
python線程開發使用標準庫threading.
thread類
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None)
target: 線程調用的對象,就是目標函數.
name: 爲線程起個名字.
args: 爲目標函數傳遞實參, 元組.
kwargs: 爲目標函數關鍵字傳參, 字典.
```
```
import threading
def worker():
print("I'm working")
print("Finished")
t = threading.Thread(target=worker, name='worker') # 線程對象.
t.start()
```
```
經過threading.Thread建立一個線程對象,target是目標函數,name能夠指定名稱.
可是線程沒有啓動,須要調用start方法.
線程會執行函數,是由於線程中就是執行代碼的,而最簡單的封裝就是函數,因此仍是函數調用.
函數執行完,線程也會隨之退出.
若是不讓線程退出,或者讓線程一直工做: 函數內部使用while循環.
```
```
import threading
import time
def worker():
while True:
time.sleep(1)
print("I'm work")
print('Finished')
t = threading.Thread(target=worker, name='worker') # 線程對象.
t.start() # 啓動.
```
```
線程退出
python沒有提供線程退出的方法,在下面狀況時會退出:
線程函數內語句執行完畢.
線程函數中拋出未處理的異常.
```
```
import threading
import time
def worker():
count = 0
while True:
if (count > 5):
raise RuntimeError()
# return
time.sleep(1)
print("I'm working")
count += 1
t = threading.Thread(target=worker, name='worker') # 線程對象.
t.start() # 啓動.
print("==End==")
```
```
python的線程沒有優先級,沒有線程組的概念,也不能被銷燬、中止、掛起,天然也沒有恢復、中斷.
```
```
import threading
import time
def add(x, y):
print('{} + {} = {}'.format(x, y, x + y, threading.current_thread()))
thread1 = threading.Thread(target=add, name='add', args=(4, 5)) # 線程對象.
thread1.start() # 啓動.
time.sleep(2)
thread2 = threading.Thread(target=add, name='add',args=(5, ), kwargs={'y': 4}) # 線程對象.
thread2.start() # 啓動.
time.sleep(2)
thread3 = threading.Thread(target=add, name='add', kwargs={'x': 4, 'y': 5}) # 線程對象.
thread3.start() # 啓動.
```
線程傳參和函數傳參沒什麼區別,本質上就是函數傳參
```
threading的屬性和方法
current_thread() # 返回當前線程對象.
main_thread() # 返回主線程對象.
active_count() # 當前處於alive狀態的線程個數.
enumerate() # 返回全部活着的線程的列表,不包括已經終止的線程和未開始的線程.
get_ident() # 返回當前線程ID,非0整數.
"active_count、enumerate方法返回的值還包括主線程"
```
```
import threading
import time
def showthreadinfo():
print('currentthread = {}'.format(threading.current_thread()))
print('main thread = {}'.format(threading.main_thread()), '"主線程對象"')
print('active count = {}'.format(threading.active_count()), '"alive"')
def worker():
count = 1
showthreadinfo()
while True:
if (count > 5):
break
time.sleep(1)
count += 1
print("I'm working")
t = threading.Thread(target=worker, name='worker') # 線程對象.
showthreadinfo()
t.start() # 啓動.
print('==END==')
```
```
thread實例的屬性和方法
name: 只是一個名稱標識,能夠重名, getName()、setName()來獲取、設置這個名詞。
ident: 線程ID, 它是非0整數。線程啓動後纔會有ID,不然爲None。線程退出,此ID依舊能夠訪問。此ID能夠重複使用。
is_alive(): 返回線程是否活着。
注: 線程的name是一個名稱,能夠重複; ID必須惟一,但能夠在線程退出後再利用。
```
```
import threading
import time
def worker():
count = 0
while True:
if (count > 5):
break
time.sleep(1)
count += 1
print(threading.current_thread().name, '~~~~~~~~~~~~~~~~~~~~~~~')
t = threading.Thread(name='worker', target=worker)
print(t.ident)
t.start()
while True:
time.sleep(1)
if t.is_alive():
print('{} {} alive'.format(t.name, t.ident))
else:
print('{} {} dead'.format(t.name, t.ident))
t.start()
```
```
start(): 啓動線程。每個線程必須且只能執行該方法一次。
run(): 運行線程函數。
爲了演示,派生一個Thread子類
```
```
# start方法.
import threading
import time
def worker():
count = 0
while True:
if (count >= 5):
break
time.sleep(1)
count += 1
print('worker running')
class MyThread(threading.Thread):
def start(self):
print('start~~~~~~~~~~~~~')
super().start()
def run(self):
print('run~~~~~~~~~~~~~~~~~')
super().run()
t = MyThread(name='worker', target=worker)
t.start()
```
```
# run方法
import threading
import time
def worker():
count = 0
while True:
if (count > 5):
break
time.sleep(1)
count += 1
print('worker running')
class MyThread(threading.Thread):
def start(self):
print('start~~~~~~~~~~~~~~~')
super().start()
def run(self):
print('run~~~~~~~~~~~~~~~~~')
super().run()
t = MyThread(name='worker', target=worker)
``````t.start()t.run() start()方法會調用run()方法,而run()方法能夠運行函數。```