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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

Python学习并发与多线程

發(fā)布時(shí)間:2025/5/22 python 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python学习并发与多线程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、并發(fā)

1.1、并發(fā)與并行

并行,parallel,同一時(shí)刻,執(zhí)行不同任務(wù),并且相互沒有干擾;

并發(fā),concurrency,一段時(shí)間內(nèi),交替執(zhí)行不同的任務(wù);

串行,一個(gè)任務(wù)執(zhí)行完成后執(zhí)行下一個(gè)任務(wù);

1.2、并發(fā)的解決方法

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

解決方法:

(1)隊(duì)列,緩沖區(qū):將任務(wù)排隊(duì),形成隊(duì)列,先進(jìn)先出,就解決了資源的使用問題;形成的隊(duì)列其實(shí)就是一個(gè)緩沖區(qū)域,假設(shè)排隊(duì)有一種優(yōu)先機(jī)制,例如女士優(yōu)先,則次隊(duì)列為優(yōu)先對列;

(2)爭搶:誰搶到資源就上鎖,排他性的鎖,其他任務(wù)只能等待;爭搶是一種高并發(fā)的解決方案,但是這樣不好,因?yàn)榭赡苡腥蝿?wù)長期霸占資源,有人一直搶不到資源;

(3)預(yù)處理:將各個(gè)任務(wù)會用到的熱點(diǎn)數(shù)據(jù)提前緩存,這樣就減少了任務(wù)的執(zhí)行時(shí)間;

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

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

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

2、進(jìn)程與線程

# 進(jìn)程與線程的關(guān)系:

程序是源碼編譯后的文件,而這些文件被存放在磁盤上;當(dāng)程序被操作系統(tǒng)加載到內(nèi)存中,就是進(jìn)程,進(jìn)程中存放著指令和數(shù)據(jù)(資源),進(jìn)程是線程的容器;線程是操作系統(tǒng)進(jìn)行運(yùn)算調(diào)度的最小單位;

2.1、線程的狀態(tài)

2.2、python中的進(jìn)程與線程

# 進(jìn)程會啟動一個(gè)解釋器進(jìn)程,線程共享一個(gè)解釋器進(jìn)程;會有一個(gè)GIL,全局解釋器鎖,來分配具體線程任務(wù)執(zhí)行;python的GIL保證同一時(shí)刻只有一個(gè)線程被執(zhí)行;

3、Python的多線程開發(fā)

3.1、Thread類

# Python的線程開發(fā)使用標(biāo)準(zhǔn)款threading;

# Thread類的初始化方法

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

參數(shù):
target  線程調(diào)用的對象,就是目標(biāo)函數(shù);
name   為線程起名
args   為目標(biāo)函數(shù)傳遞位置參數(shù),元祖;
kwargs  為目標(biāo)函數(shù)傳遞關(guān)鍵字參數(shù),字典

(1)線程的啟動:

通過threading.Thread創(chuàng)建一個(gè)線程對象,target是目標(biāo)函數(shù),name指定線程名稱,到此線程被創(chuàng)建完成,需要調(diào)用start() 方法來啟動線程 ;

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

(2)線程的退出:

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

①:線程函數(shù)內(nèi)語句執(zhí)行完成;

②:線程函數(shù)中拋出未處理異常;

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

(3)線程的傳參

# 線程的傳參本質(zhì)上和函數(shù)沒有區(qū)別

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

(4)threading的屬性和方法

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

# main_thread() 返回主線程對象

# active_count() 返回處于alive狀態(tài)的線程數(shù)

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

# get_ident() 返回當(dāng)前線程的id,非0整數(shù)

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

# name:線程名稱

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

# is_alive():是否存活

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

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

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, ()) # 啟動一個(gè)線程except Exception:with _active_limbo_lock:del _limbo[self]raiseself._started.wait()

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

def run(self):try:if self._target:self._target(*self._args, **self._kwargs) # 執(zhí)行target函數(shù)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、多線程

#? 多線程,一個(gè)進(jìn)程中如果有多個(gè)線程,就是多線程,實(shí)現(xiàn)一種并發(fā);

# 一個(gè)進(jìn)程中至少有一個(gè)線程,并作為程序的入口,這個(gè)線程就是主線程;一個(gè)進(jìn)程至少有一個(gè)主線程,其他線程為工作線程;

# 線程安全與線程不安全

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()運(yùn)行結(jié)果: 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分析: 看代碼,應(yīng)該是一行行打印,但是很多字符串打印在了一起? 說明print函數(shù)被打斷了,被線程切換打斷了,print函數(shù)分2步,第一步打印字符串,第二步打印換行,就在2步之間被打斷,發(fā)生了線程切換 每個(gè)線程是根據(jù)系統(tǒng)調(diào)用cpu分時(shí)計(jì)算的,可能出現(xiàn)線程1的函數(shù)還沒有執(zhí)行完成,則cpu資源被線程2給搶占,則去執(zhí)行線程2的函數(shù); 解決方法:字符串是不可變數(shù)據(jù)類型,它作為一個(gè)整體不可分割輸出,end=''不再讓print換行,但沒有解決根本問題,應(yīng)為print函數(shù)是線程不安全

3.3、daemon線程與non-daemon線程

# 注意:daemon不是linux中的守護(hù)進(jìn)程,daemon屬性必須在start方法之前設(shè)置好;

在主線程運(yùn)行結(jié)束后會檢查是否含有,沒有執(zhí)行完成的non-daemon線程,
如果有則等待non-daemon線程運(yùn)行完成;
沒有則直接結(jié)束線程;

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

# 總結(jié):

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

②:如果不設(shè)置daemon,就取當(dāng)前線程的daemon來設(shè)置它;

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

④:從主線程創(chuàng)建的所有線程不設(shè)置daemon,則默認(rèn)daemon=False,也就是non-daemon線程;

⑤:Python程序在沒有活的non-daemon線程運(yùn)行時(shí)退出,也就是剩下的只能是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線程結(jié)束以后才結(jié)束; print('main thread end')''' 運(yùn)行結(jié)果: 0 1 2 . . 9 main thread end分析:由于t1.join()方法后,將主線程阻塞,等待t1線程結(jié)束; '''

# join(timeout=None),是線程的標(biāo)準(zhǔn)方法之一;

# 一個(gè)線程中調(diào)用另外一個(gè)線程的join方法,調(diào)用著將被阻塞,直到被調(diào)用線程終止;

# 一個(gè)線程可以被join多次,timout參數(shù)指定調(diào)用則等待多久,沒有設(shè)置超時(shí)時(shí)間,就一直等待到被調(diào)用者線程終止;設(shè)置超時(shí)時(shí)間如果被調(diào)線程沒有結(jié)束,則調(diào)用者不等待,直接結(jié)束線程;

# 調(diào)用誰的join方法,就是join誰,就要等待誰;

4、threading.local類

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

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

# 每一個(gè)線程的id為key,元祖為value;

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

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()''' 運(yùn)行結(jié)構(gòu): <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、定時(shí)器Timer

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

# 它的實(shí)例就是能延時(shí)執(zhí)行目標(biāo)函數(shù)的線程,在真正執(zhí)行目標(biāo)函數(shù)之前,都可以cancel它;

# cancel方法本質(zhì)使用Event類實(shí)現(xiàn);

# 自定義實(shí)現(xiàn)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() # 在這里起一個(gè)線程是為了避免在主線程被阻塞,執(zhí)行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')

?

轉(zhuǎn)載于:https://www.cnblogs.com/soulgou123/p/9877593.html

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。