ThreadLocal是用來做什麼的?
阿新 • • 發佈:2018-12-22
真真應了那句話,書讀百遍,其意自現。何況大多數時候,你只需要重複一遍就行了,廢話不多說。
一,首先來看看這樣一些問題的區別:
1. 多程序之間如何通訊?
因為不同的程序會在記憶體中被分配不同的資源。所以多程序之間通訊是一個問題,python的multiprocessing模組一共了一系列的交換方式,Queue, Pipe, Manager。
2. 多執行緒之間如何通訊?
這就不是一個問題,因為執行緒間是共享所在程序變數的。所以通訊不是問題,讓它們同步才是問題,同步暫且不表。
3. 不同程序間執行緒如何通訊?
這也不是個問題,因為這就是兩個程序之間的通訊。
4. 一個執行緒內部如何通訊?
可能乍一看,覺得這也能是個問題?但,這才是真正的問題。
二,下面進入正題,看程式碼
import threading def a(x): print('a thread %d' % x) b(x) def b(x): print('b thread %d' % x) t1 = threading.Thread(target=a, args=(3,)) t2 = threading.Thread(target=a, args=(5,)) t1.start() t1.join() t2.start() t2.join() Output: a thread 3 b thread 3 a thread 5 b thread 5
開啟執行緒呼叫a方法,然後a方法呼叫b方法。 可以看到,t1,t2兩個執行緒裡的x是不同的x。
所以,執行緒內部兩個函式通訊,可以用引數來傳遞。但這顯然不是一個好的方法,當函式數量上去或著互動的資料很多,那一層層傳參就崩潰了。
那麼直接用全域性變數?看效果
import threading x = 0 def a(): print('a thread %d' % x) b() def b(): print('b thread %d' % x) t1 = threading.Thread(target=a) t2 = threading.Thread(target=a) t1.start() t1.join() t2.start() t2.join() Output: a thread 0 b thread 0 a thread 0 b thread 0
我們的目的是為了讓不同的執行緒,維護不同的x,但是因為x是程序的,所以就只有一份,達不到目的。
三,解決方案
前面達不到目的,是因為程序中的x只有一份,大家都能訪問,那麼我們在程序中把x做成多份,一個執行緒對應一份不就行了?那麼要實現執行緒和特定的x一一對應,那就是map了,在python中,使用dict。
import threading
dict = {}
def a(x):
dict[threading.current_thread()] = x
print('a thread %d' % x)
b()
def b():
print('b thread %d' % dict[threading.current_thread()])
t1 = threading.Thread(target=a, args=(3,))
t2 = threading.Thread(target=a, args=(5,))
t1.start()
t1.join()
t2.start()
t2.join()
Output:
a thread 3
b thread 3
a thread 5
b thread 5
可以看到,在程序中維護了一個dict,然後用每個執行緒的current_thread()去對映它們各自的x變數。完成了要求。
上面雖然完成了要求,不過怎麼看都是野路子,所以ThreadLocal來了。
import threading
dict = threading.local()
def a(x):
dict.x = x
print('a thread %d' % dict.x)
b()
def b():
print('b thread %d' % dict.x)
t1 = threading.Thread(target=a, args=(3,))
t2 = threading.Thread(target=a, args=(5,))
t1.start()
t1.join()
t2.start()
t2.join()
Output:
a thread 3
b thread 3
a thread 5
b thread 5
其實原理都一樣,不過是python做得太好,什麼都封裝,有些問題看起來就不那麼直觀了。