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

歡迎訪問 生活随笔!

生活随笔

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

python

python多线程 不在main_Python多线程

發(fā)布時間:2025/3/15 python 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python多线程 不在main_Python多线程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、線程概念

在程序運行時,操作系統(tǒng)會創(chuàng)建一個進程,并且會創(chuàng)建一個線程,這個線程就是主線程,主線程可以創(chuàng)建子線程。線程看上去同時運行,其實是按照并發(fā)執(zhí)行的,走走停停,一直到所有形線程完成為止。線程像進程一樣會有生命周期,如下所示:

將程序進行多線程編程,其性能會得到很大提升。python線程對CPU密集型性能提高不大,對I/O密集型性能提高很大。

二、多線程示例

import threading

import time

class myThread(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

out() #加入執(zhí)行的程序代碼

def out():

print_time1()

print_time2()

def print_time1():

print("Locka is acquired")

print("Lockb is acwuired")

def print_time2():

print("Lockb is acquired")

time.sleep(2)

print("Locka is acwuired")

def main():

for i in range(50):

t = myThread()

t.start() #執(zhí)行線程

main()

以上就是線程的簡單程序,我們創(chuàng)建了50個線程,將他們同時運行。他們完成的時間不一樣,其先后順序也不能確定。使用方法就是自己寫一個類,繼承threading.Thread類,并重寫方法run(),將自己要運行的程序放入run()函數(shù)之中就行。

但是,上述程序有一個問題,就是在調(diào)用函數(shù)out()時,可能在一個線程還沒有執(zhí)行完時,就暫停,CPU轉(zhuǎn)而去執(zhí)行另一個線程,導(dǎo)致另一個線程修改了這個線程的數(shù)據(jù),導(dǎo)致輸出錯誤的結(jié)果。解決辦法就是在同一時刻就只能有一個線程訪問臨界資源,其他線程只能等待。

三、線程同步

在python中實現(xiàn)線程同步有多種方法

1. 線程鎖(Lock)

GIL(全局解釋器鎖)

GIL并不是Python的特性,它是在實現(xiàn)Python解析器(CPython)時所引入的一個概念,是為了實現(xiàn)不同線程對共享資源訪問的互斥,才引入了GIL。以下是原理圖:

我們對臨界資源加上鎖,這樣其他線程就無法訪問,直到這個線程完成操作,釋放線程鎖之后為止。如下代碼:

import threading

import time

#創(chuàng)建鎖

locka = threading.Lock()

lockb = threading.Lock()

class myThread(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

out()

def out():

print_time1()

print_time2()

def print_time1():

locka.acquire() #獲取鎖

print("Locka is acquired")

lockb.acquire() #獲取鎖

print("Lockb is acwuired")

lockb.release() #釋放鎖

locka.release() #釋放鎖

def print_time2():

lockb.acquire()

print("Lockb is acquired")

time.sleep(2)

locka.acquire()

print("Locka is acwuired")

locka.release()

lockb.release()

def main():

for i in range(50):

t = myThread()

t.start()

main()

在上面程序中,我們創(chuàng)建了兩個鎖locka和lockb,分別對臨界資源加鎖,這樣就可以讓同一時刻就只有一個線程執(zhí)行,避免輸出錯誤結(jié)果。但是上述代碼還有一個錯誤,當(dāng)?shù)谝粋€線程執(zhí)行到函數(shù)print_time2()的time_sleep(2)時,需要獲取鎖locka,但是locka已經(jīng)被第二個線程獲取,還沒有釋放,而且第二個線程也需要獲取lockb才能繼續(xù)運行,但是lockb已被第一個線程獲取,還沒有釋放,就這樣,兩個線程會一直等待,陷入死鎖。解決辦法是引入可重入鎖。

2.遞歸鎖(RLock)

遞歸鎖就是在同一個線程中可以獲取鎖所多次,不會陷入死鎖。但是在acquire()n次之后,需要release()n次。

import threading

import time

rlock = threading.RLock() #RLock本身有一個計數(shù)器,如果碰到acquire,那么計數(shù)器+1

#如果計數(shù)器大于0,那么其他線程無法查收,如果碰到release,計數(shù)器-1

class myThread(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

out()

def out():

print_time1()

print_time2()

def print_time1():

rlock.acquire() #獲取鎖

print("Locka is acquired")

rlock.acquire() #獲取鎖

print("Lockb is acwuired")

rlock.release() #釋放鎖

rlock.release() #釋放鎖

def print_time2():

rlock.acquire()

print("Lockb is acquired")

time.sleep(2)

rlock.acquire()

print("Locka is acwuired")

rlock.release()

rlock.release()

def main():

for i in range(50):

t = myThread()

t.start()

main()

三、Semaphore(信號量)

threading模塊里的Semaphore類實現(xiàn)了信號量對象,可用于控制獲取資源的線程數(shù)量。所具有的acquire()和release()方法,可以用with語句的上下文管理器。當(dāng)進入時,將調(diào)用acquire()方法,當(dāng)退出時,將調(diào)用release()。

import threading

import time

sem = threading.Semaphore(3) #設(shè)置線程并發(fā)數(shù)

class myThread(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

out()

def out():

print_time1()

print_time2()

def print_time1():

sem.acquire() #線程數(shù)減一

print("Locka is acquired")

print("Lockb is acwuired")

sem.release() #線程數(shù)加一

def print_time2():

sem.acquire() #線程數(shù)減一

print("Lockb is acquired")

print("Locka is acwuired")

sem.release() #線程數(shù)加一

def main():

for i in range(10):

t = myThread()

t.start()

main()

四、Condition(條件變量)

Condition(條件變量)通常與一個鎖關(guān)聯(lián)。需要在多個Contidion中共享一個鎖時,可以傳遞一個Lock/RLock實例給構(gòu)造方法,否則它將默認生成一個RLock實例。

可以認為,除了Lock帶有的鎖定池外,Condition還包含一個等待池,池中的線程處于狀態(tài)圖中的等待阻塞狀態(tài),直到另一個線程調(diào)用notify()/notifyAll()通知;得到通知后線程進入鎖定池等待鎖定。

Condition():

acquire(): 線程鎖

release(): 釋放鎖

wait(timeout): 線程掛起,并釋放鎖,直到收到一個notify通知或者超時(可選的,浮點數(shù),單位是秒s)才會被喚醒繼續(xù)運行。wait()必須在已獲得Lock前提下才能調(diào)用,否則會觸發(fā)RuntimeError。

notify(n=1): 調(diào)用這個方法將從等待池挑選一個線程并通知,收到通知的線程將自動調(diào)用acquire()嘗試獲得鎖定(進入鎖定池);其他線程仍然在等待池中。調(diào)用這個方法不會釋放鎖定。使用前線程必須已獲得鎖定,否則將拋出異常。 最多喚醒n個等待的線程。

notifyAll(): 調(diào)用這個方法將通知等待池中所有的線程,這些線程都將進入鎖定池嘗試獲得鎖定。調(diào)用這個方法不會釋放鎖定。使用前線程必須已獲得鎖定,否則將拋出異常。

以下就以生產(chǎn)者消費者為例:

import threading

import time

import random

con = threading.Condition()

class Goods():

def __init__(self):

self.__goods = 0

def getgoods(self):

return self.__goods

def add(self):

self.__goods += 1

def sub(self):

self.__goods -= 1

def isEmpty(self):

if self.__goods <= 0:

return True

else:

return False

def isFull(self):

if self.__goods >= 10:

return True

else:

return False

class Producer(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

while True:

con.acquire()#獲取鎖

while goods.isFull(): #貨物滿了,需要消費才能生產(chǎn),進入阻塞

con.wait()

goods.add()#生產(chǎn)一件貨物

print("生產(chǎn)一件貨物,總貨物數(shù)量為:", goods.getgoods())

con.notifyAll()#生產(chǎn)一件貨物后便喚醒所有正在等待的消費者

con.release()#釋放鎖

time.sleep(random.random())

class Consumer(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

while True:

con.acquire()#獲取鎖

while goods.isEmpty():#貨物消費完了,需要生產(chǎn)貨物,進入阻塞

con.wait()

goods.sub()#消費一件貨物

print("消費一件貨物,總貨物數(shù)量為:", goods.getgoods())

con.notifyAll()#消費一件貨物后便喚醒所有正在等待的生產(chǎn)者

con.release()#釋放鎖

time.sleep(random.random())

goods = Goods()

def main():

threads = []

#threads.append(Producer())

#threads.append(Comsumer())

for i in range(5):

threads.append(Producer())

for i in range(5):

threads.append(Consumer())

for th in threads:

th.start()

main()

五、同步隊列

讓我們考慮更復(fù)雜的一種場景:產(chǎn)品是各不相同的。這時只記錄一個數(shù)量就不夠了,還需要記錄每個產(chǎn)品的細節(jié)。很容易想到需要用一個容器將這些產(chǎn)品記錄下來。

Python的Queue模塊中提供了同步的、線程安全的隊列類,包括FIFO(先入先出)隊列Queue,LIFO(后入先出)隊列LifoQueue,和優(yōu)先級隊列PriorityQueue。這些隊列都實現(xiàn)了鎖原語,能夠在多線程中直接使用。可以使用隊列來實現(xiàn)線程間的同步。

用FIFO隊列實現(xiàn)上述生產(chǎn)者與消費者問題的代碼如下:

import threading

import time

import random

import queue

q = queue.Queue() #創(chuàng)建一個線程同步隊列

class Producer(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

while True:

item = random.randint(0, 16)

while q.qsize() >= 10:

pass

q.put(item)    #添加貨物

print("生產(chǎn)貨物%02d, 隊列大小:%02d" % (item, q.qsize()))

time.sleep(random.randint(0, 3))

class Consumer(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

while True:

item = q.get()   #消費貨物,若為空,會阻塞

print("消費貨物%02d, 隊列大小:%02d" % (item, q.qsize()))

time.sleep(random.randint(0, 3))

def main():

threads = []

for i in range(5):

threads.append(Producer())

for i in range(5):

threads.append(Consumer())

for th in threads:

th.start()

main()

六、Event(事件)

python線程的事件用于主線程控制其他線程的執(zhí)行,事件主要提供了三個方法wait、clear、set。

事件處理的機制:全局定義了一個“Flag”,如果“Flag”值為 False,那么當(dāng)程序執(zhí)行 event.wait 方法時就會阻塞,如果“Flag”值為True,那么event.wait 方法時便不再阻塞。

event.set() 設(shè)置標志位為True

event.clear() 清空標志位,標志位為False

event.wait() 等待設(shè)置標志位,阻塞

event.isSet() 判斷標志位是True還是False

下面就采用紅綠燈車通行的例子來示例:

import threading

import time

event = threading.Event()

def Lighter():

event.set()

count = 0

while True:

if count > 5 and count <= 10: #紅燈

event.clear() #清除標志位

elif count > 10: #變?yōu)榫G燈

event.set() #重新設(shè)置標志位

count = 0

time.sleep(1)

count += 1

def Car(name):

while True:

if event.isSet(): #判斷標志位為True

print("light is green, %d is running" % name)

time.sleep(2)

else:

print("light is red, %d is waiting" % name)

event.wait() #阻塞,停車

def main():

light = threading.Thread(target=Lighter)

light.start()

threads = []

for i in range(5): #開五部車

threads.append(threading.Thread(target=Car, args=(i,)))

for car in threads:

car.start()

main()

這個程序?qū)⒓t綠燈的情況來控制車的通行,即用紅綠燈這線程來控制車線程,達到一個線程控制多個線程的目的。

總結(jié)

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

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