Python必學(xué)知識(shí)點(diǎn)總結(jié)
1. txt文件讀取,考點(diǎn):分批讀取文件內(nèi)容,避免內(nèi)存不足的情況;
## 一次性全部讀到內(nèi)存
def get_lines():
with open('file.txt','rb') as f:
return f.readlines()
## 分批讀到內(nèi)存,避免內(nèi)存不足;
def get_line():
data_list = list()
with open('file.txt','rb') as f:
data_item = f.readlines(60000)
data_list.append(data_item)
yield data_list
if __name__ == '__main__':
for e in get_lines():
process(e) # 處理每一行數(shù)據(jù)2. 獲取文件夾下面所有文件路徑,包括多重文件夾
import os
## 遞歸獲取所有文件
def get_files_path(root_dir):
file_path_list = list()
for item in os.listdir(root_dir):
item_path = os.path.join(root_dir,item)
if os.path.isdir(item_path):
file_path_list.extend(get_files_path(item_path))
else:
file_path_list.append(item_path)
return file_path_list
## 非遞歸,并且只需要“.jpg“文件
def get_file_path_list(path,file_type=".jpg"):
data_list = list()
for root,dirs,files in os.walk(path):
for file in files:
if file.endswith(file_type):
data_list.append(os.path.join(root,file))
return data_list3. 判斷這一天是這一年的第幾天
import datetime
def day_of_year(year:int,month:int,day:int):
date1 = datetime.date(year=int(year),month=int(month),day=int(day))
date2 = datetime.date(year=int(year),month=int(1),day=int(1))
return (date1-date2).days+14. 字典、列表操作
## 字典推導(dǎo)式
d1 = {key:len(key) for key in ("test","python")}
## 字符串反轉(zhuǎn)(對(duì)key進(jìn)行反轉(zhuǎn))
d2 = {key[::-1]:value for (key,value) in d1.items()}
## 字典合并
d = dict(d1,**d2)
## 按key排序
dict(sorted(d.items(), key=lambda item: item[1]))
## 按value排序
dict(sorted(d.items(), key=lambda item: item[0]))
## 打亂list
import random
list1 = list(d.values()) # 返回的是一個(gè) dict_keys 對(duì)象,不再是 list 類(lèi)型,也不支持 index 索引
random.shuffle(list1)
## list元素去重
set_list = list(set(d1.values()))
## list元素排序
sorted_list = sorted(list1)
## list元素刪除
sorted_list.remove(sorted_list[0])
## list 元素過(guò)濾
sorted_list = filter(lambda x:x>0,sorted_list)
## 找兩個(gè)List的相同元素
set(d1.values())&set(d2.values())
## 找兩個(gè)List的不相同元素
set(d1.keys())&set(d2.keys())
## 列表解析、列表推導(dǎo)式,并將字符串類(lèi)型的key值全部大寫(xiě)
sorted_list = [item.upper() for item in list(d.keys())]5. python新式類(lèi)和經(jīng)典類(lèi)的區(qū)別
a.在python里凡是繼承了object的類(lèi),都是新式類(lèi);
b....6. python中內(nèi)置的數(shù)據(jù)結(jié)構(gòu)有哪些
整型int、長(zhǎng)整型long、浮點(diǎn)型float、復(fù)數(shù)complex、字符串str、
列表list、元組tuple、字典dict、集合set
python3中沒(méi)有l(wèi)ong,只有無(wú)限精度的int7. 可變類(lèi)型和不可變類(lèi)型
1. 可變類(lèi)型有l(wèi)ist,dict;不可變類(lèi)型有string,number,tuple.
2. 當(dāng)進(jìn)行修改操作時(shí),可變類(lèi)型傳遞的是內(nèi)存中的地址,也就是說(shuō),直接修改內(nèi)存中的值,并沒(méi)有開(kāi)辟新的內(nèi)存。
3. 不可變類(lèi)型被改變時(shí),并沒(méi)有改變?cè)瓋?nèi)存地址中的值,而是開(kāi)辟一塊新的內(nèi)存,將原地址中的值復(fù)制過(guò)去,對(duì)這塊新開(kāi)辟的內(nèi)存中的值進(jìn)行操作。8. python中的super()
Python中的super(Net, self).__init__()是指首先找到Net的父類(lèi)(比如是類(lèi)NNet),
然后把類(lèi)Net的對(duì)象self轉(zhuǎn)換為類(lèi)NNet的對(duì)象,然后“被轉(zhuǎn)換”的類(lèi)NNet對(duì)象調(diào)用自己的init函數(shù),
其實(shí)簡(jiǎn)單理解就是子類(lèi)把父類(lèi)的__init__()放到自己的__init__()當(dāng)中,
這樣子類(lèi)就有了父類(lèi)的__init__()的那些東西。
super()如果不寫(xiě)參數(shù)的話(huà),那么默認(rèn)就是super(當(dāng)前類(lèi), self)。9. Python中類(lèi)方法、類(lèi)實(shí)例方法、靜態(tài)方法有何區(qū)別
類(lèi)方法:是類(lèi)對(duì)象的方法,在定義時(shí)需要在上方使用@classmethod進(jìn)行裝飾,形參為cls,表示類(lèi)對(duì)象,類(lèi)對(duì)象和實(shí)例對(duì)象都可調(diào)用;
類(lèi)實(shí)例方法:是類(lèi)實(shí)例化對(duì)象的方法,只有實(shí)例對(duì)象可以調(diào)用,形參為self,指代對(duì)象本身;
靜態(tài)方法:是一個(gè)任意函數(shù),在其上方使用@staticmethod進(jìn)行裝飾,可以用對(duì)象直接調(diào)用,靜態(tài)方法實(shí)際上跟該類(lèi)沒(méi)有太大關(guān)系;10. Python單例
import threading
class Singleton(object):
_instance_lock = threading.Lock() # 如果不加鎖,那么單例功能會(huì)有失效的情況。
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"): # 如果該類(lèi)“不“含有實(shí)例化對(duì)象
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
# 用父類(lèi)(object)的new方法創(chuàng)建一個(gè)該類(lèi)(cls==Singleton)的實(shí)例。
Singleton._instance = object.__new__(cls)
return Singleton._instance
obj1 = Singleton()
obj2 = Singleton()
print(obj1,obj2)
def task(arg):
obj = Singleton()
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()11. 請(qǐng)描述抽象類(lèi)和接口類(lèi)的區(qū)別和聯(lián)系
1.抽象類(lèi):規(guī)定了一系列的方法,并規(guī)定了必須由繼承類(lèi)實(shí)現(xiàn)的方法。由于有抽象方法的存在,所以抽象類(lèi)不能實(shí)例化。
可以將抽象類(lèi)理解為毛坯房,門(mén)窗,墻面的樣式由你自己來(lái)定,所以抽象類(lèi)與作為基類(lèi)的普通類(lèi)的區(qū)別在于約束性更強(qiáng)。
2.接口類(lèi):與抽象類(lèi)很相似,表現(xiàn)在接口中定義的方法,必須由引用類(lèi)實(shí)現(xiàn),但他與抽象類(lèi)的根本區(qū)別在于用途:
與不同個(gè)體間溝通的規(guī)則,你要進(jìn)宿舍需要有鑰匙,這個(gè)鑰匙就是你與宿舍的接口,你的舍友也有這個(gè)接口,
所以他也能進(jìn)入宿舍,你用手機(jī)通話(huà),那么手機(jī)就是你與他人交流的接口。
3.區(qū)別和關(guān)聯(lián):
a.接口是抽象類(lèi)的變體,接口中所有的方法都是抽象的,而抽象類(lèi)中可以有非抽象方法,抽象類(lèi)是聲明方法的存在而不去實(shí)現(xiàn)它的類(lèi);
b.接口可以繼承,抽象類(lèi)不行;
c.接口定義方法,沒(méi)有實(shí)現(xiàn)的代碼,而抽象類(lèi)可以實(shí)現(xiàn)部分方法;
d.接口中基本數(shù)據(jù)類(lèi)型為static而抽象類(lèi)不是;12. 編寫(xiě)函數(shù)的4個(gè)原則
1.函數(shù)設(shè)計(jì)要盡量短小;
2.函數(shù)聲明要做到合理、簡(jiǎn)單、易于使用;
3.函數(shù)參數(shù)設(shè)計(jì)應(yīng)該考慮向下兼容;
4.一個(gè)函數(shù)只做一件事情,盡量保證函數(shù)語(yǔ)句粒度的一致性;13. 什么是lambda函數(shù)?有什么好處?
lambda 函數(shù)是一個(gè)可以接收任意多個(gè)參數(shù)(包括可選參數(shù))并且返回單個(gè)表達(dá)式值的函數(shù);
1.lambda函數(shù)比較輕便,即用即扔,很適合需要完成一項(xiàng)功能,但是此功能只在此一處使用,連名字都很隨意的情況下;
2.匿名函數(shù),一般用來(lái)給filter,map這樣的函數(shù)式編程服務(wù);
3.作為回調(diào)函數(shù),傳遞給某些應(yīng)用,比如消息處理;
14. 什么是閉包
在函數(shù)內(nèi)部再定義一個(gè)函數(shù),并且這個(gè)函數(shù)用到了外邊函數(shù)的變量,那么將這個(gè)函數(shù)以及用到的一些變量稱(chēng)之為閉包。15. Python中的yield
yield類(lèi)似return會(huì)停止,但是不會(huì)結(jié)束。yield作為可迭代的 generator(生成器)對(duì)象,
每次迭代的時(shí)候會(huì)在yield語(yǔ)句后停止。
def simple_generator():
x = 2
yield x**2
yield x**3
yield x**4
generator_object = simple_generator()
[item for item in generator_object]
#[4, 8, 16]16. Python實(shí)現(xiàn)私用變量的效果
1. 單下劃線(xiàn)表示的私有,但是依然可以直接訪(fǎng)問(wèn);
2. 雙下劃線(xiàn)表示的私有,因?yàn)楸粡?qiáng)制改名,所以不可以直接訪(fǎng)問(wèn),但訪(fǎng)問(wèn)這個(gè)改成的變量名;
class Rect:
def __init__(self,area):
self.__area = area
@property
def area(self):
return self.__area
rect = Rect(30)
#直接通過(guò)方法名來(lái)訪(fǎng)問(wèn) area 方法
print("矩形的面積是:",rect.area)
#假私有,_Rect__area就是__area新的變量名。
rect._Rect__area17. 進(jìn)程、線(xiàn)程、協(xié)程
進(jìn)程:程序運(yùn)行在操作系統(tǒng)上的一個(gè)實(shí)例,就稱(chēng)之為進(jìn)程。進(jìn)程需要相應(yīng)的系統(tǒng)資源:內(nèi)存、時(shí)間片、pid。
一個(gè)運(yùn)行的程序就是一個(gè)進(jìn)程,沒(méi)有運(yùn)行的代碼叫程序。
進(jìn)程是系統(tǒng)資源分配的最小單位,進(jìn)程擁有自己獨(dú)立的內(nèi)存空間,所有進(jìn)程間數(shù)據(jù)不共享,且開(kāi)銷(xiāo)大。
多進(jìn)程:適合CPU密集操作(cpu指令比較多,如位多的浮點(diǎn)運(yùn)算)。
線(xiàn)程:cpu調(diào)度執(zhí)行的最小單位,也叫執(zhí)行路徑,不能獨(dú)立存在,依賴(lài)進(jìn)程存在。一個(gè)進(jìn)程至少有一個(gè)線(xiàn)程,叫做主線(xiàn)程。
而多個(gè)線(xiàn)程共享內(nèi)存(數(shù)據(jù)共享,共享全局變量),從而極大的提高了程序的運(yùn)行效率。
多線(xiàn)程:適合IO密集性操作(讀寫(xiě)數(shù)據(jù)操作比較多的,比如爬蟲(chóng));
協(xié)程:是一種用戶(hù)態(tài)的輕量級(jí)線(xiàn)程,協(xié)程的調(diào)度完全由用戶(hù)控制。協(xié)程擁有自己的寄存器上下文和棧。
協(xié)程調(diào)度時(shí),將寄存器上下文和棧保存到其它地方,在切回來(lái)的時(shí)候,恢復(fù)先前保存的寄存器上下文和棧,
直接操作棧基本沒(méi)有內(nèi)核切換的開(kāi)銷(xiāo),可以不加鎖的訪(fǎng)問(wèn)全局變量,所以上下文的切換非常快。
三者關(guān)系:進(jìn)程里面有線(xiàn)程,線(xiàn)程里面有協(xié)程。
線(xiàn)程是并發(fā),進(jìn)程是并行。
并行:同一時(shí)刻多個(gè)任務(wù)同時(shí)運(yùn)行;
并發(fā):不會(huì)在同一時(shí)刻同時(shí)運(yùn)行,存在交替執(zhí)行的情況。18. Python異步的使用場(chǎng)景
1. 不涉及共享資源,或者對(duì)于共享資源只讀等非互斥操作;
2. 沒(méi)有時(shí)序上的嚴(yán)格關(guān)系;
3. 不需要原子操作,或可以通過(guò)其它方式控制原子性;
4. 常用于IO操作等耗時(shí)操作,因?yàn)楸容^影響客戶(hù)體驗(yàn)和使用性能;
5. 不影響主線(xiàn)程邏輯。
所謂原子操作是指不會(huì)被 線(xiàn)程調(diào)度 機(jī)制打斷的操作;這種操作一旦開(kāi)始,就一直運(yùn)行到結(jié)束,中間不會(huì)有任何 context switch (切換到另一個(gè)線(xiàn)程)。19. 什么是多線(xiàn)程競(jìng)爭(zhēng)
線(xiàn)程是非獨(dú)立的,同一個(gè)進(jìn)程里線(xiàn)程是數(shù)據(jù)共享的,當(dāng)各個(gè)線(xiàn)程訪(fǎng)問(wèn)數(shù)據(jù)資源時(shí)會(huì)出現(xiàn)競(jìng)爭(zhēng)狀態(tài),
即:數(shù)據(jù)幾乎同步被多個(gè)線(xiàn)程占有,造成數(shù)據(jù)混亂,即所謂的線(xiàn)程不安全。為此可添加鎖。
鎖是Python提供的對(duì)線(xiàn)程控制的對(duì)象。有互斥鎖,可重入鎖,死鎖。
鎖的好處:確保某段關(guān)鍵代碼(共享數(shù)據(jù)資源)只能由一個(gè)線(xiàn)程從頭到尾完整地執(zhí)行;能解決資源競(jìng)爭(zhēng)下的原子操作問(wèn)題。
鎖的壞處:阻止了多線(xiàn)程并發(fā)執(zhí)行,包含鎖的某段代碼實(shí)際上只能以單線(xiàn)程模式執(zhí)行,效率大大下降。20. Python的線(xiàn)程同步
1. setDaemon(False),當(dāng)一個(gè)進(jìn)程啟動(dòng)之后,會(huì)默認(rèn)產(chǎn)生一個(gè)主線(xiàn)程,因?yàn)榫€(xiàn)程時(shí)程序執(zhí)行的最小單位。
當(dāng)設(shè)置多線(xiàn)程時(shí),主線(xiàn)程會(huì)創(chuàng)建多個(gè)子線(xiàn)程。在Python中,默認(rèn)情況下就是setDaemon(False),
主線(xiàn)程執(zhí)行完自己的任務(wù)以后就退出。此時(shí)子線(xiàn)程會(huì)繼續(xù)執(zhí)行自己的任務(wù),直到自己的任務(wù)結(jié)束。
2. setDaemon(True),這時(shí)子線(xiàn)程為守護(hù)線(xiàn)程,主線(xiàn)程一旦執(zhí)行結(jié)束,則全部子線(xiàn)程被強(qiáng)制終止。
3. join(線(xiàn)程同步),join所完成的工作就是線(xiàn)程同步,即主線(xiàn)程任務(wù)結(jié)束以后,進(jìn)入堵塞狀態(tài),
一直等待所有的子線(xiàn)程結(jié)束以后,主線(xiàn)程再終止。
當(dāng)設(shè)置守護(hù)線(xiàn)程時(shí),含義是主線(xiàn)程對(duì)于子線(xiàn)程等待timeout的時(shí)間將會(huì)殺死該子線(xiàn)程,最后退出程序。
所以說(shuō),如果有10個(gè)子線(xiàn)程,全部等待時(shí)間就是每個(gè)timeout的累加和。
如果沒(méi)有設(shè)置守護(hù)線(xiàn)程時(shí),主線(xiàn)程將會(huì)等待timeout的累加和這樣的一段時(shí)間,時(shí)間一到,主線(xiàn)程結(jié)束,
但是子線(xiàn)程依然存活,并且持續(xù)運(yùn)行,直到子線(xiàn)程全部結(jié)束,程序退出。(孤兒進(jìn)程)
import threading
import time
def thread():
time.sleep(2)
print('---子線(xiàn)程結(jié)束---')
def main():
t1 = threading.Thread(target=thread)
t1.setDaemon(True) # 設(shè)置子線(xiàn)程守護(hù)主線(xiàn)程
t1.start()
t1.join(timeout=1) # 線(xiàn)程同步,主線(xiàn)程堵塞1s,然后主線(xiàn)程結(jié)束,子線(xiàn)程繼續(xù)執(zhí)行;
# 如果不設(shè)置timeout參數(shù)就等子線(xiàn)程結(jié)束后主線(xiàn)程再結(jié)束;
# 如果設(shè)置了setDaemon=True和timeout=1主線(xiàn)程等待1s后會(huì)強(qiáng)制殺死子線(xiàn)程,然后主線(xiàn)程結(jié)束。
print('---主線(xiàn)程結(jié)束---')
main()21. 死鎖
定義:若干子線(xiàn)程在系統(tǒng)資源競(jìng)爭(zhēng)的時(shí)候,都在等待對(duì)方對(duì)某部分資源解除占用狀態(tài),結(jié)果誰(shuí)也不愿意先解鎖,程序無(wú)法執(zhí)行下去。
GIL鎖:全局解釋器鎖;
作用:限制多線(xiàn)程同時(shí)執(zhí)行,保證同一時(shí)間只有一個(gè)線(xiàn)程執(zhí)行,所以cpython里的多線(xiàn)程其實(shí)是偽多線(xiàn)程。
python里常常使用協(xié)程技術(shù)來(lái)代替多線(xiàn)程,協(xié)程是一種更輕量級(jí)的線(xiàn)程。
進(jìn)程和線(xiàn)程的切換是由系統(tǒng)決定,而協(xié)程由開(kāi)發(fā)者決定,而模塊gevent下切換是遇到了耗時(shí)操作時(shí)才會(huì)切換。22. 多線(xiàn)程交互訪(fǎng)問(wèn)數(shù)據(jù),如何避免重讀。
創(chuàng)建一個(gè)已訪(fǎng)問(wèn)數(shù)據(jù)列表,用于存儲(chǔ)已經(jīng)訪(fǎng)問(wèn)過(guò)的數(shù)據(jù),并加上互斥鎖,
在多線(xiàn)程訪(fǎng)問(wèn)數(shù)據(jù)的時(shí)候先查看數(shù)據(jù)是否在已訪(fǎng)問(wèn)的列表中,若存在就跳過(guò)。23. 線(xiàn)程安全、互斥鎖
每個(gè)對(duì)象都對(duì)應(yīng)于一個(gè)可稱(chēng)為”互斥鎖“的標(biāo)記,這個(gè)標(biāo)記用來(lái)保證在任一時(shí)刻,只能有一個(gè)線(xiàn)程訪(fǎng)問(wèn)該對(duì)象。
同一進(jìn)程中的多線(xiàn)程之間共享系統(tǒng)資源,多個(gè)線(xiàn)程同時(shí)對(duì)一個(gè)對(duì)象進(jìn)行操作,一個(gè)線(xiàn)程操作尚未結(jié)束,另一線(xiàn)程已經(jīng)對(duì)其進(jìn)行操作,
導(dǎo)致最終結(jié)果出現(xiàn)錯(cuò)誤,此時(shí)需要對(duì)被操作對(duì)象添加互斥鎖,保證每個(gè)線(xiàn)程對(duì)該對(duì)象的操作都得到正確的結(jié)果。24. 同步、異步、阻塞,非阻塞
同步:多個(gè)任務(wù)之間有先后執(zhí)行順序,一個(gè)執(zhí)行完下個(gè)才能執(zhí)行。
異步:多個(gè)任務(wù)之間沒(méi)有先后順序,可以同時(shí)執(zhí)行,有時(shí)候一個(gè)任務(wù)可能要在必要的時(shí)候獲取另一個(gè)同時(shí)執(zhí)行的任務(wù)結(jié)果(回調(diào)操作)。
阻塞:如果卡住了調(diào)用者,調(diào)用者不能繼續(xù)往下執(zhí)行,指的就是調(diào)用者發(fā)生阻塞。
非阻塞:如果不會(huì)卡住,可以繼續(xù)執(zhí)行,指的就是非阻塞。
同步、異步相對(duì)于多任務(wù)而言,阻塞非阻塞相對(duì)于代碼執(zhí)行而言。25. 什么是僵尸進(jìn)程、孤兒進(jìn)程
孤兒進(jìn)程:父進(jìn)程退出,子進(jìn)程還在運(yùn)行的這些子進(jìn)程都是孤兒進(jìn)程,孤兒進(jìn)程將被init進(jìn)程(進(jìn)程號(hào)為1)所收養(yǎng),
并由init進(jìn)程對(duì)他們的完成狀態(tài)進(jìn)行收集。
僵尸進(jìn)程:進(jìn)程使用fork創(chuàng)建子進(jìn)程,如果子進(jìn)程退出,而父進(jìn)程并沒(méi)有調(diào)用wait/waitpid獲取子進(jìn)程的狀態(tài)信息,
那么子進(jìn)程的進(jìn)程描述符仍然保存在系統(tǒng)中的這些進(jìn)程。
避免僵尸進(jìn)程的方法:
1. fork兩次用孫子進(jìn)程去完成子進(jìn)程的任務(wù);
2. 用wait()函數(shù)使父進(jìn)程阻塞;
3. 使用信號(hào)量,在signal handler中調(diào)用waitpid,這樣父進(jìn)程不用阻塞。26. 多線(xiàn)程共同操作同一個(gè)數(shù)據(jù)互斥鎖同步
上鎖解鎖過(guò)程
當(dāng)一個(gè)線(xiàn)程調(diào)用鎖的 acquire() 方法獲得鎖時(shí),鎖就進(jìn)入“locked”狀態(tài)。
每次只有一個(gè)線(xiàn)程可以獲得鎖。
如果此時(shí)另一個(gè)線(xiàn)程試圖獲得這個(gè)鎖,該線(xiàn)程就會(huì)變?yōu)椤?/span>blocked”狀態(tài),稱(chēng)為“阻塞”,
直到擁有鎖的線(xiàn)程調(diào)用鎖的 release() 方法釋放鎖之后,鎖進(jìn)入“unlocked”狀態(tài)。
線(xiàn)程調(diào)度程序從處于同步阻塞狀態(tài)的線(xiàn)程中選擇一個(gè)來(lái)獲得鎖,并使得該線(xiàn)程進(jìn)入運(yùn)行(running)狀態(tài)。
import threading
import time
g_num = 0
def test1(num):
global g_num
for i in range(num):
mutex.acquire() # 上鎖
g_num += 1
mutex.release() # 解鎖
print("---test1---g_num=%d" % g_num)
def test2(num):
global g_num
for i in range(num):
mutex.acquire() # 上鎖
g_num += 1
mutex.release() # 解鎖
print("---test2---g_num=%d" % g_num)
# 創(chuàng)建一個(gè)互斥鎖
# 默認(rèn)是未上鎖的狀態(tài)
mutex = threading.Lock()
# 創(chuàng)建2個(gè)線(xiàn)程,讓他們各自對(duì)g_num加10000次
p1 = threading.Thread(target=test1, args=(10000,))
p1.start()
p2 = threading.Thread(target=test2, args=(10000,))
p2.start()
"""
enumerate() 是 Python 中線(xiàn)程模塊的內(nèi)置方法。
它用于返回當(dāng)前處于活動(dòng)狀態(tài)的所有 Thread 類(lèi)對(duì)象的列表。
它還包括守護(hù)線(xiàn)程、主線(xiàn)程和由 current_thread() 創(chuàng)建的虛擬線(xiàn)程對(duì)象。
它不計(jì)算已終止或尚未啟動(dòng)的線(xiàn)程。
"""
# 等待計(jì)算完成
while len(threading.enumerate()) != 1:
time.sleep(0.1)
print("2個(gè)線(xiàn)程對(duì)同一個(gè)全局變量操作之后的最終結(jié)果是:%s" % g_num)
27. 進(jìn)程通信隊(duì)列與進(jìn)程池
由于不同進(jìn)程之間不通信,所以采用隊(duì)列。
由于需要控制進(jìn)程數(shù)量,所以有了進(jìn)程池。過(guò)多的進(jìn)程數(shù)量并不高效。
def read_data(queue):
# 循環(huán)讀取數(shù)據(jù)
while True:
# 判斷隊(duì)列是否為空
if queue.qsize() == 0:
print("隊(duì)列為空~")
break
# 從隊(duì)列中讀取數(shù)據(jù)
result = queue.get()
print(result)
if __name__ == '__main__':
# 創(chuàng)建進(jìn)程池
pool = multiprocessing.Pool(2)
# 創(chuàng)建進(jìn)程池隊(duì)列
queue = multiprocessing.Manager().Queue()
# 在進(jìn)程池中的進(jìn)程間進(jìn)行通信
# 使用線(xiàn)程池同步的方式,先寫(xiě)后讀
# pool.apply(write_data, (queue, )) # 同步方式加載
# pool.apply(read_data, (queue, )) # 同步方式加載
# apply_async() 返回ApplyResult 對(duì)象
result = pool.apply_async(write_data, (queue, )) # 異步方式加載
# ApplyResult對(duì)象的wait() 方法,表示后續(xù)進(jìn)程必須等待當(dāng)前進(jìn)程執(zhí)行完再繼續(xù)
result.wait() # 由于異步方式加載,但是必須寫(xiě)先完成,所以必須等待寫(xiě)進(jìn)程完成
pool.apply_async(read_data, (queue, )) # 異步方式加載
pool.close()
# 異步后,主線(xiàn)程不再等待子進(jìn)程執(zhí)行結(jié)束,再結(jié)束
# join() 后,表示主線(xiàn)程會(huì)等待子進(jìn)程執(zhí)行結(jié)束后,再結(jié)束
pool.join()公眾號(hào)粉絲禮包:后臺(tái)關(guān)鍵詞:
python大禮包
整理不易,還請(qǐng)點(diǎn)擊在看與分享,謝謝。
