[TOC]
一、python線程模塊的選擇
Python提供了幾個(gè)用于多線程編程的模塊, 包括thread、threading和Queue等 。thread和threading模塊允許程序員創(chuàng)建和管理線程。thread模塊提供了基本的線程和鎖的支持,threading提供了更高級(jí)別、功能更強(qiáng)的線程管理的功能。Queue模塊允許用戶創(chuàng)建一個(gè)可以用于多個(gè)線程之間共享數(shù)據(jù)的隊(duì)列數(shù)據(jù)結(jié)構(gòu)。
避免使用thread模塊,因?yàn)楦呒?jí)別的threading模塊更為先進(jìn),對(duì)線程的支持更為完善,而且使用thread模塊里的屬性有可能會(huì)與threading出現(xiàn)沖突;其次低級(jí)別的thread模塊的同步原語(yǔ)很少(實(shí)際上只有一個(gè)),而threading模塊則有很多;再者,thread模塊中當(dāng)主線程結(jié)束時(shí),所有的線程都會(huì)被強(qiáng)制結(jié)束掉,沒(méi)有警告也不會(huì)有正常的清除工作, 至少threading模塊能確保重要的子線程退出后進(jìn)程才退出 。
thread模塊不支持守護(hù)線程 ,當(dāng)主線程退出時(shí),所有的子線程不論它們是否還在工作,都會(huì)被強(qiáng)行退出。而threading模塊支持守護(hù)線程,守護(hù)線程一般是一個(gè)等待客戶請(qǐng)求的服務(wù)器,如果沒(méi)有客戶提出請(qǐng)求它就在那等著,如果設(shè)定一個(gè)線程為守護(hù)線程,就表示這個(gè)線程是不重要的,在進(jìn)程退出的時(shí)候,不用等待這個(gè)線程退出。
二、threading模塊
multiprocess模塊的完全模仿了threading模塊的接口,二者在使用層面,有很大的相似性,因而不再詳細(xì)介紹(官方鏈接)
三、開(kāi)啟子線程的兩種方式
線程的開(kāi)啟和進(jìn)程不同,進(jìn)程是拷貝一份代碼去內(nèi)存中執(zhí)行。內(nèi)部調(diào)用的是fork創(chuàng)建子進(jìn)程
而線程是會(huì)去執(zhí)行的指定函數(shù)
- 通過(guò)指定函數(shù)的方式
- 通過(guò)類的繼承,實(shí)現(xiàn)run方法
方式1:
# 方式一
def task(name):
print(f'{name} start')
global x
x -= 1
print({name}, x)
time.sleep(2)
print(f'{name} end')
if __name__ == '__main__':
x = 10
t1 = Thread(target=task,args=("線程1",))
t2 = Thread(target=task,args=("線程2",))
t1.start() # 告訴操作系統(tǒng)開(kāi)一個(gè)線程
t2.start() # 告訴操作系統(tǒng)開(kāi)一個(gè)線程
print('主')
線程1 start {'線程1'} 9 線程2 start {'線程2'} 8 主 線程1 end 線程2 end
方式2
# 方式二
class Mythread(Thread):
def __init__(self,name):
super().__init__()
self.name = name
def run(self):
print(f'{self.name} start')
global x
x -= 1
print({self.name}, x)
time.sleep(2)
print(f'{self.name} end')
if __name__ == '__main__':
x = 10
t1 = Mythread("線程1")
t2 = Mythread("線程2")
t1.start()
t2.start()
print('主')
線程1 start {'線程1'} 9 線程2 start {'線程2'} 8 主 線程1 end 線程2 end
通過(guò)上面兩組代碼你會(huì)發(fā)現(xiàn):線程的創(chuàng)建運(yùn)行比進(jìn)程快,同一個(gè)進(jìn)程中的線程可以共享資源
四、join回收子線程
和進(jìn)程一樣,等待所以子線程結(jié)束然后去回收
from threading import Thread
import time
'''
等待回收子線程
'''
def task():
print('子線程 start')
time.sleep(2)
print('子線程 end')
t = Thread(target=task)
t.start()
t.join() # 等待子線程運(yùn)行結(jié)束
print('主線程')
五、Thread類的其他方法
Thread實(shí)例對(duì)象的方法:
-
isAlive()
:返回線程是否活動(dòng)的。 -
getName()
:返回線程名。 -
setName()
:設(shè)置線程名。
threading模塊提供的一些方法:
-
threading.currentThread()
:返回當(dāng)前的線程變量。 -
threading.enumerate()
:返回一個(gè)包含正在運(yùn)行的線程的list。正在運(yùn)行指線程啟動(dòng)后、結(jié)束前,不包括啟動(dòng)前和終止后的線程。 -
threading.activeCount()
:返回正在運(yùn)行的線程數(shù)量,與len(threading.enumerate())有相同的結(jié)果。
from threading import Thread,currentThread,enumerate,activeCount
import time
'''
線程的其他用法:
1.查看是否存在 is_alive() # True or False
2.獲取線程名 getName()
3.設(shè)置線程名 setName(name)
4.當(dāng)前線程 currentThread() 需要從threading導(dǎo)入currentThread模塊
5.活動(dòng)線程總和 activeCount() 需要從threading導(dǎo)入activeCount模塊
6.查看所有線程 enumerate() 需要從threading導(dǎo)入enumerate模塊
'''
def task():
print('子線程 start')
time.sleep(2)
print('子線程 end')
if __name__ == '__main__':
t1 = Thread(target=task)
t2 = Thread(target=task)
t1.start()
t2.start()
print("查看線程狀態(tài),設(shè)置線程名,獲取線程名","-" * 50)
print(t1.is_alive()) # 查看是否存在
print(t2.is_alive()) # 查看是否存在
t1.setName("子線程一") # 設(shè)置線程1名字
t2.setName("子線程二") # 設(shè)置線程2名字
print(t1.getName()) # 獲取線程名
print(t2.getName()) # 獲取線程名
print("查看當(dāng)前線程","-" * 50)
print(currentThread()) # 查看當(dāng)前線程
print(currentThread().name) # 查看當(dāng)前線程名
print("查看所有線程","-"*50)
print(activeCount()) # 查看存活線程個(gè)數(shù)
print(enumerate()) # 查看所有線程
print(len(enumerate())) # 查看所有線程個(gè)數(shù)
六、基于多線程實(shí)現(xiàn)socket多用戶間通訊
客戶端
import socket
from threading import Thread
def task(conn,client_addr):
# 通訊循環(huán)
while 1:
try:
msg = conn.recv(1024)
if not msg:
break
print(client_addr,"消息:",msg.decode("utf8"))
msg = input("請(qǐng)輸入內(nèi)容")
conn.send(msg.encode("utf8"))
except Exception as e:
print(e)
break
if __name__ == '__main__':
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(("127.0.0.1",8080))
server.listen(5)
# 鏈接循環(huán)
while 1:
print("等待連接...")
conn, addr = server.accept()
print(addr,"連接成功")
t = Thread(target=task,args=(conn,addr))
t.start()
客戶端
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(("127.0.0.1",8080))
while 1:
msg = input("請(qǐng)輸入內(nèi)容")
client.send(msg.encode("utf8"))
data = client.recv(1024)
if not data:
break
print(data.decode("utf8"))
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
