真真应了那句话,书读百遍,其意自现。何况大多数时候,你只需要重复一遍就行了,废话不多说。
一,首先来看看这样一些问题的区别:
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做得太好,什么都封装,有些问题看起来就不那么直观了。