日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python学习并发与多线程

發布時間:2025/5/22 python 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python学习并发与多线程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、并發

1.1、并發與并行

并行,parallel,同一時刻,執行不同任務,并且相互沒有干擾;

并發,concurrency,一段時間內,交替執行不同的任務;

串行,一個任務執行完成后執行下一個任務;

1.2、并發的解決方法

“高并發模型”:例如早高峰的北京地鐵,在同一時刻,需要處理大量任務,可以理解為高并發模型;

解決方法:

(1)隊列,緩沖區:將任務排隊,形成隊列,先進先出,就解決了資源的使用問題;形成的隊列其實就是一個緩沖區域,假設排隊有一種優先機制,例如女士優先,則次隊列為優先對列;

(2)爭搶:誰搶到資源就上鎖,排他性的鎖,其他任務只能等待;爭搶是一種高并發的解決方案,但是這樣不好,因為可能有任務長期霸占資源,有人一直搶不到資源;

(3)預處理:將各個任務會用到的熱點數據提前緩存,這樣就減少了任務的執行時間;

(4)并行:開辟多的資源,例如銀行辦理業務,排隊的人多了,可以多增加業務窗口;此方案為水平擴展的思想;

(5)提速:簡單的就是提高資源性能,提高cpu性能或者單個服務器安裝更多的cpu,此方案為垂直擴展

(6)消息中間件:模型可以理解為北京地鐵站外面的排隊走廊,具有緩沖人流量的功能;常見的消息隊列有:RabbitMQ、ActiveMQ、RocketMQ(阿里)、kafka等

2、進程與線程

# 進程與線程的關系:

程序是源碼編譯后的文件,而這些文件被存放在磁盤上;當程序被操作系統加載到內存中,就是進程,進程中存放著指令和數據(資源),進程是線程的容器;線程是操作系統進行運算調度的最小單位;

2.1、線程的狀態

2.2、python中的進程與線程

# 進程會啟動一個解釋器進程,線程共享一個解釋器進程;會有一個GIL,全局解釋器鎖,來分配具體線程任務執行;python的GIL保證同一時刻只有一個線程被執行;

3、Python的多線程開發

3.1、Thread類

# Python的線程開發使用標準款threading;

# Thread類的初始化方法

def __init__(self, group=None, target=None, name=None,args=(), kwargs=None, *, daemon=None):

參數:
target  線程調用的對象,就是目標函數;
name   為線程起名
args   為目標函數傳遞位置參數,元祖;
kwargs  為目標函數傳遞關鍵字參數,字典

(1)線程的啟動:

通過threading.Thread創建一個線程對象,target是目標函數,name指定線程名稱,到此線程被創建完成,需要調用start() 方法來啟動線程 ;

import threading
def work():print('I m working')print('Finished')t=threading.Thread(target=work,name='workerthread') # 創建線程t t.start() # 啟動線程t

(2)線程的退出:

# python沒有提供線程的退出方法,但是線程在以下情況會退出:

①:線程函數內語句執行完成;

②:線程函數中拋出未處理異常;

# python的線程沒有優先級、沒有線程組的概念,也不能被銷毀,停止,掛起,也沒有恢復和中斷;

(3)線程的傳參

# 線程的傳參本質上和函數沒有區別

import threadingdef add(x,y):print(x+y)t=threading.Thread(target=add,args=(4,5),name='workerthread') # args=(4,5)傳遞位置參數; t.start()

(4)threading的屬性和方法

# current_thread()? 返回當前線程對象

# main_thread() 返回主線程對象

# active_count() 返回處于alive狀態的線程數

# enumerate() 返回所有活著的線程列表,不包括已經終止的線程和未開始的線程

# get_ident() 返回當前線程的id,非0整數

(5)Thread實例的屬性和方法

# name:線程名稱

# ident:線程id,線程啟動后才有id,否則為None

# is_alive():是否存活

# start()方法與run()方法

①:start() 啟動線程,每一個線程必須并且只能執行一次該方法;

def start(self):if not self._initialized:raise RuntimeError("thread.__init__() not called")if self._started.is_set():raise RuntimeError("threads can only be started once")with _active_limbo_lock:_limbo[self] = selftry:_start_new_thread(self._bootstrap, ()) # 啟動一個線程except Exception:with _active_limbo_lock:del _limbo[self]raiseself._started.wait()

②:run()  并不啟動新線程,只是在主線程中調用了一個函數,調用定義線程對象中的target函數;

def run(self):try:if self._target:self._target(*self._args, **self._kwargs) # 執行target函數finally:# Avoid a refcycle if the thread is running a function with# an argument that has a member that points to the thread.del self._target, self._args, self._kwargs

?

3.2、多線程

#? 多線程,一個進程中如果有多個線程,就是多線程,實現一種并發;

# 一個進程中至少有一個線程,并作為程序的入口,這個線程就是主線程;一個進程至少有一個主線程,其他線程為工作線程;

# 線程安全與線程不安全

def worker():for x in range(100):print('{} is runing'.format(threading.current_thread().name))for x in range(1,5):name='work-{}'.format(x)t= threading.Thread(target=worker,name=name)t.start()運行結果: work-1 is runing work-2 is runingwork-1 is runingwork-3 is runingwork-4 is runing work-3 is runingwork-2 is runingwork-1 is runing分析: 看代碼,應該是一行行打印,但是很多字符串打印在了一起? 說明print函數被打斷了,被線程切換打斷了,print函數分2步,第一步打印字符串,第二步打印換行,就在2步之間被打斷,發生了線程切換 每個線程是根據系統調用cpu分時計算的,可能出現線程1的函數還沒有執行完成,則cpu資源被線程2給搶占,則去執行線程2的函數; 解決方法:字符串是不可變數據類型,它作為一個整體不可分割輸出,end=''不再讓print換行,但沒有解決根本問題,應為print函數是線程不安全

3.3、daemon線程與non-daemon線程

# 注意:daemon不是linux中的守護進程,daemon屬性必須在start方法之前設置好;

在主線程運行結束后會檢查是否含有,沒有執行完成的non-daemon線程,
如果有則等待non-daemon線程運行完成;
沒有則直接結束線程;

源碼中Thread的 __init__方法中 if daemon is not None:self._daemonic=daemon # 設定daemon的布爾值 ,true為daemon,false為non-daemon else:self._daemonic=current_thread().daemon # 如果為None則從父線程獲取;

# 總結:

①:線程具有一個daemon屬性,可以顯示設置為True或False,也可以不設置,則默認為None;

②:如果不設置daemon,就取當前線程的daemon來設置它;

③:主線程是non-daemon,即daemon=False;

④:從主線程創建的所有線程不設置daemon,則默認daemon=False,也就是non-daemon線程;

⑤:Python程序在沒有活的non-daemon線程運行時退出,也就是剩下的只能是daemon線程,主線程才能退出,否則主線程只能等待;

3.4、join方法

import time import threadingdef foo(n):for i in range(n):print(i)time.sleep(1)t1=threading.Thread(target=foo,args=(10,),daemon=True) t1.start() t1.join() # 表示主線程,必須等到t1線程結束以后才結束; print('main thread end')''' 運行結果: 0 1 2 . . 9 main thread end分析:由于t1.join()方法后,將主線程阻塞,等待t1線程結束; '''

# join(timeout=None),是線程的標準方法之一;

# 一個線程中調用另外一個線程的join方法,調用著將被阻塞,直到被調用線程終止;

# 一個線程可以被join多次,timout參數指定調用則等待多久,沒有設置超時時間,就一直等待到被調用者線程終止;設置超時時間如果被調線程沒有結束,則調用者不等待,直接結束線程;

# 調用誰的join方法,就是join誰,就要等待誰;

4、threading.local類

# python提供的threading.local類,將這個類實例化得到一個全局對象,但是不同的線程使用這個對象存儲數據其他線程看不見;

# 本質:threading.local類構建了一個大字典,存放所有線程相關的字典,定義如下: { id(Thread) -> (ref(Thread), thread-local dict) }

# 每一個線程的id為key,元祖為value;

# value中2部分為:線程對象引用,每個線程自己的字典;

from threading import local import threading import timea=local()def worker():a.x=0for i in range(10):# print(a.__dict__,current_thread().ident)time.sleep(0.0001)a.x+=1print(threading.current_thread(),a.x,a.__dict__)for i in range(5):threading.Thread(target=worker).start()''' 運行結構: <Thread(Thread-3, started 14488)> 10 {'x': 10} <Thread(Thread-4, started 14420)> 10 {'x': 10} <Thread(Thread-5, started 13620)> 10 {'x': 10} <Thread(Thread-1, started 11808)> 10 {'x': 10} <Thread(Thread-2, started 15348)> 10 {'x': 10} '''

5、定時器Timer

# Timer是線程Thread的子類,就是線程類,具有線程的屬性和方法;

# 它的實例就是能延時執行目標函數的線程,在真正執行目標函數之前,都可以cancel它;

# cancel方法本質使用Event類實現;

# 自定義實現Timer類:

class MyTimer:def __init__(self,interval,func,args=(),kwargs={}):self.interval=intervalself.func=funcself.args=argsself.kwargs=kwargsself.event=Event()def cancel(self):print("call cancel------>")self.event.set()def start(self):Thread(target=self._run).start() # 在這里起一個線程是為了避免在主線程被阻塞,執行cancel方法不生效的問題def _run(self):self.event.wait(self.interval)if not self.event.is_set():self.func(*self.args,**self.kwargs)# Thread(target=self.func,args=self.args,kwargs=self.kwargs).start() self.event.set()def add(x,y):print(3,'========>',x + y)t1=MyTimer(3,add,(4,5))t1.start() t1.cancel()print('Main Thread end')

?

轉載于:https://www.cnblogs.com/soulgou123/p/9877593.html

總結

以上是生活随笔為你收集整理的Python学习并发与多线程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。