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

歡迎訪問 生活随笔!

生活随笔

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

python

python多线程 不在main_Python多线程

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

一、線程概念

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

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

二、多線程示例

import threading

import time

class myThread(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

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

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() #執行線程

main()

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

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

三、線程同步

在python中實現線程同步有多種方法

1. 線程鎖(Lock)

GIL(全局解釋器鎖)

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

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

import threading

import time

#創建鎖

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()

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

2.遞歸鎖(RLock)

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

import threading

import time

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

#如果計數器大于0,那么其他線程無法查收,如果碰到release,計數器-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類實現了信號量對象,可用于控制獲取資源的線程數量。所具有的acquire()和release()方法,可以用with語句的上下文管理器。當進入時,將調用acquire()方法,當退出時,將調用release()。

import threading

import time

sem = threading.Semaphore(3) #設置線程并發數

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() #線程數減一

print("Locka is acquired")

print("Lockb is acwuired")

sem.release() #線程數加一

def print_time2():

sem.acquire() #線程數減一

print("Lockb is acquired")

print("Locka is acwuired")

sem.release() #線程數加一

def main():

for i in range(10):

t = myThread()

t.start()

main()

四、Condition(條件變量)

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

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

Condition():

acquire(): 線程鎖

release(): 釋放鎖

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

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

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

以下就以生產者消費者為例:

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(): #貨物滿了,需要消費才能生產,進入阻塞

con.wait()

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

print("生產一件貨物,總貨物數量為:", goods.getgoods())

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

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():#貨物消費完了,需要生產貨物,進入阻塞

con.wait()

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

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

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

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()

五、同步隊列

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

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

用FIFO隊列實現上述生產者與消費者問題的代碼如下:

import threading

import time

import random

import queue

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

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("生產貨物%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線程的事件用于主線程控制其他線程的執行,事件主要提供了三個方法wait、clear、set。

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

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

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

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

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: #變為綠燈

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

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()

這個程序將紅綠燈的情況來控制車的通行,即用紅綠燈這線程來控制車線程,達到一個線程控制多個線程的目的。

總結

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

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