数据同步

多线程和多进程最大的不同在于多进程中,同一个变量各自有一份拷贝在每个进程中,互不影响;而多线程中,所有变量都由所有线程共享。所以这就导致了一个问题,任何一个变量都可以被任何一个线程修改,因此线程使用中最大的危险在于多个线程同时操作一个变量造成的内容混乱。

解决这个问题的一种方案是使用锁。threading模块中就提供了Lock类来完成这个操作。具体使用可参考以下示例。

import time, threading

balance = 0
lock = threading.Lock()

def change(n):
	global balance
	balance += n
	balance -= n

def run_thread(n):
	for i in range(100000):
		lock.acquire()
		try:
			change(n)
		finally:
			lock.release()

t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

当多个线程同时执行lock.acquire()时,只有一个线程能够得到锁,然后继续执行代码。获得锁的线程在结束的时候必须释放锁,即调用lock.release(),否则其他未获得锁的线程将永远等待,造成死锁。锁的使用实际上降低了执行效率,在实际使用中需要仔细考虑数据同步的问题。

在一个线程中,使用自己的局部变量肯定比使用全局变量要好,因为局部变量只有自己可见,而全局变量还需要加锁,但是局部变量也存在调用时参数传递繁琐的问题。threading模块中提供的ThreadLocal类就提供了在全局为每个线程保存数据的功能。具体使用可参考以下示例。

import threading

local_school = threading.local()

def process_student():
	std = local_school.student
	print('Hello, {} (in {})'.format(std, threading.current_thread().name))

def process_thread(name):
	local_school.student = name
	process_student()

t1 = threading.Thread(target=process_thread, args=('Kate',), name='Thread-t1')
t2 = threading.Thread(target=process_thread, args=('Michael',), name='Thread-t2')
t1.start()
t2.start()
t1.join()
t2.join()