程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Communication between threads in Python

編輯:Python

Python中線程間通信

  • 一、前言
  • 二、什麼是互斥鎖
  • 三、使用互斥鎖
  • 四、Communicate between threads using queues
  • 五、Two things to note about threads


一、前言

We already know that information cannot be shared directly between processes,So can information be shared between threads?Let's verify it with an example.定義一個全局變量g_num,分別創建2個子進程對g_num執行不同的操作,並輸出操作後的結果.代碼如下:

# _*_ coding:utf-8 _*_
from threading import Thread # 導入線程
import time
def plus():
print("-------子線程1開始---------")
global g_num # 定義全局變量
g_num += 50 # Global variable value plus50
print("g_num is %d" % g_num)
print("-------子線程1結束---------")
def minus():
time.sleep(2)
print("-------子線程2開始---------")
global g_num # 定義全局變量
g_num -= 50 # Global variable value is decremented50
print("g_num is %d" % g_num)
print("-------子線程2結束---------")
g_num = 100 # 定義一個全局變量
if __name__ == "__main__":
print("----------主線程開始-------------")
print("g_num is %d" % g_num)
t1 = Thread(target=plus) # 實例化線程t1
t2 = Thread(target=minus) # 實例化線程t2
t1.start() # 開啟線程t1
t2.start() # 開啟線程t2
t1.join() # 等待t1線程結束
t2.join() # 等待t2線程結束
print("--------主線程結束-------------")

上述代碼中,定義一個全局變量g_num,賦值為100,然後創建2個線程.一個線程將g_num增加50,一個線程將g_num減少50.如果g_num的最終結果為100,It means that data can be shared between threads,運行結果如下圖所示:

從上面的例子可以得出,在一個進程內的所有線程共享全局變量,能夠在不使用其他方式的前提下完成多線程之間的數據共享.


二、什麼是互斥鎖

Because threads can modify global variables at will,This may result in confusing operations on threads between multiple threads.以房子為例,When there is only one occupant in the house(單線程),He can use any room at any time,such as kitchen、Bedroom and bathroom etc.但是,When the house has multiple occupants(多線程),He cannot use certain rooms at any time,such as a bathroom,否則會造成混亂.

如何解決這個問題呢?一個防止他人進入的簡單方法,Just put a lock on the door.It's the first person to line up at the door,等鎖打開再進去.如圖所示:

這就是“互斥鎖”(Mutual exclude,縮寫Mutex),防止多個線程同時讀寫某一塊內存區域.互斥鎖為資源引入一個狀態:鎖定和非鎖定.某個線程要更改共享數據時,先將其鎖定,此時資源的狀態為“鎖定”,其他線程不能更改;直到該線程釋放資源,將資源的狀態變成“非鎖定”時,其他的線程才能再次鎖定該資源.互斥鎖保證了每次只有一個線程進行寫入操作,Thereby ensuring the accuracy of the data in the case of multi-threading.


三、使用互斥鎖

在threading模塊中使用LockClasses can handle locking conveniently.Lock類有兩個方法:acquire()鎖定和release()釋放鎖.Example usage is as follows:

mutex = threading.Lock() # 創建鎖
mutex.acquire([blocking]) # 鎖定
mutex.release() # 釋放鎖

語法如下:

acquire([blocking]) :獲取鎖定,如果有必要,Needs to block until the lock is released.如果提供blockingparameter will be set toFalse,Returns immediately when the lock cannot be acquiredFalse;Returns if the lock was successfully acquiredTrue.

release():釋放一個鎖定,When the lock is in the unlocked state,Or call from and originalacquire()A different thread of the method calls this method,將出現錯誤.

下面,Learn how to use mutexes with an example.Here, multi-threading and mutex lock simulation are used to realize the function of multiple people ordering movie tickets at the same time,Suppose a movie theater has only one show100張電影票,10Users snapped up the movie tickets at the same time.One per sale,Displays the number of movie tickets remaining at one time.代碼如下:

# _*_ coding:utf-8 _*_
from threading import Thread, Lock
import time
n = 100 # 共100張票
def task():
global n
mutex.acquire() # 上鎖
temp = n # 賦值給臨時變量
time.sleep(0.1) # 休眠0.1秒
n = temp - 1 # 數量減1
print("購買成功,剩余%d張電影票" % n)
mutex.release() # 釋放鎖
if __name__ == "__main__":
mutex = Lock() # 實例化Lock類
t_l = [] # 初始化一個列表
for i in range(10):
t = Thread(target=task) # 實例化線程類
t_l.append(t) # Store the thread instance in the list
t.start() # 創建線程
for t in t_l:
t.join() # 等待子線程結束

上述代碼中,創建了10個線程,全部執行task()函數.為了解決資源競爭問題,使用mutex.acquire() The function implements resource locking,After the first thread to acquire the resource locks,其他線程等待 mutex.release() 解鎖,So only one thread executes at a timetask()函數.運行結果如下圖所示:


注意:
使用互斥鎖時,要避免死鎖.在多任務系統下,When one or more threads are waiting for a system resource,When the resource is occupied by the thread itself or other threads,It's a deadlock,如圖所示:


四、Communicate between threads using queues

我們知道multiprocessing 模塊的QueueQueues enable inter-process communication,Also between threads,也可以使用QueueQueues implement inter-thread communication.The difference is that we need to usequeue 模塊的Queue隊列,而不是multiprocessing模塊的Queue隊列,但是Queue的使用方法相同.

使用QueueCommunication between threads is usually used in production-consumption patterns.Modules that produce data are called producers,The modules that process the data are called consumers.The buffer between producers and consumers is called a warehouse.Producers are responsible for transporting goods to warehouses,The consumer is responsible for removing the goods from the warehouse,This constitutes the production and consumption pattern.下面通過一個示例學習一下使用QueueCommunication between threads.

定義一個生產者類Producer,定義一個消費者類Consumer.生產者生成5件產品,Write to the queue sequentially,Consumers, in turn, take products from the queue,代碼如下:

# _*_ coding:utf-8 _*_
from queue import Queue
import random, threading, time
# 生產者類
class Producer(threading.Thread):
def __init__(self, name, queue):
threading.Thread.__init__(self, name=name)
self.data = queue
def run(self):
for i in range(5):
print("生產者%s將產品%d加入隊列!" % (self.getName(), i))
self.data.put(i)
time.sleep(random.random())
print("生產者%s完成" % self.getName())
# 消費者類
class Consumer(threading.Thread):
def __init__(self, name, queue):
threading.Thread.__init__(self, name=name)
self.data = queue
def run(self):
for i in range(5):
val = self.data.get()
print("消費者%s將產品%d從隊列中取出!" % (self.getName(), val))
time.sleep(random.random())
print("消費者%s完成" % self.getName())
if __name__ == "__main__":
print("----------主線程開始------------")
queue = Queue() # 實例化隊列
producer = Producer("Producer", queue) # 實例化線程Producer,And pass in the queue as a parameter
consumer = Consumer("Consumer", queue) # 實例化線程Consumer,And pass in the queue as a parameter
producer.start() # 啟動線程Producer
consumer.start() # 啟動線程Consumer
producer.join() # 等待線程Producer結束
consumer.join() # 等待線程Consumer結束
print("----------主線程結束--------------")

運行結果如下圖所示:

注意:
由於程序中使用了random.random()函數生成0-1之間的隨機數,Therefore, the results of your operation may not be the same as the picture.


五、Two things to note about threads

【1】進程和線程的區別

進程和線程的區別主要有:

(1)A process is a unit in which the system allocates and schedules resources,線程是一個實體,是CPU調度和分派的基本單位.

(2)Processes are independent of each other,多進程中,同一個變量,A separate copy exists in each process,但互不影響;而同一個進程的多個線程是內存共享的,所有變量都由所有線程共享.

(3)由於進程間是獨立的,Therefore, the crash of one process will not affect other processes;而線程是包含在進程之內的,A thread crash can cause a process to crash,This in turn causes other processes within the same process to crash.


【2】Whether to lock multi-threaded non-global variables

在多線程開發中,全局變量是多個線程都共享的數據,為了防止數據混亂,Mutexes are usually used.而局部變量等是各自線程的,是非共享的,So there is no need to use a mutex.



  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved