1、线程间的信号
虽然我们使用多线程是为了同时运行多个操作,不过有时我们也需要同步它们。在线程间安全通信的方式可以使用事件对象。每个 Event (事件)内部都有一个标记,我们可以用 set() 和 clear() 方法控制它。其他线程可以使用 wait() 来暂停直到标记被设置才重新启动,使用这方法可以有效阻塞执行。
def wait_for_event(e):
"""做任何事前先等待事件被设置。"""
logging.debug('wait_for_event starting')
# 一直阻塞直到事件被设置
event_is_set = e.wait()
logging.debug('event set: %s', event_is_set)
def wait_for_event_timeout(e, t):
"""等待 t 秒。"""
while not e.is_set():
logging.debug('wait_for_event_timeout starting')
event_is_set = e.wait(t)
logging.debug('event set: %s', event_is_set)
if event_is_set:
logging.debug('processing event')
else:
logging.debug('doing other work')
logging.basicConfig(
level=logging.DEBUG,
format='(%(threadName)-10s) %(message)s',
)
e = threading.Event()
t1 = threading.Thread(
name='block',
target=wait_for_event,
args=(e,),
)
t1.start()
t2 = threading.Thread(
name='nonblock',
target=wait_for_event_timeout,
args=(e, 2),
)
t2.start()
logging.debug('Waiting before calling Event.set()')
time.sleep(5)
e.set()
logging.debug('Event is set')
2、控制资源访问
除了同步多个线程的操作,控制共享资源的访问以防止污染或丢失数据也是非常重要的。 Python 的内置数据结构(列表(list),字典(dict)等....)都是线程安全的,有「原子操作」的对象都是这样。(全局解释器锁会保护这样的 Python 内部数据结构在更新时线程不会被释放)。其他 Python 的数据结构或者说较简单的类型如整数浮点数则不会受此保护。我们可以使用 Lock 对象来保护某对象的访问。
import logging
import random
import threading
import time
class Counter:
def __init__(self, start=0):
self.lock = threading.Lock()
self.value = start
def increment(self):
logging.debug('Waiting for lock')
self.lock.acquire()
try:
logging.debug('Acquired lock')
self.value = self.value + 1
finally:
self.lock.release()
def worker(c):
for i in range(2):
pause = random.random()
logging.debug('Sleeping %0.02f', pause)
time.sleep(pause)
c.increment()
logging.debug('Done')
logging.basicConfig(
level=logging.DEBUG,
format='(%(threadName)-10s) %(message)s',
)
counter = Counter()
for i in range(2):
t = threading.Thread(target=worker, args=(counter,))
t.start()
logging.debug('Waiting for worker threads')
main_thread = threading.main_thread()
for t in threading.enumerate():
if t is not main_thread:
t.join()
logging.debug('Counter: %d', counter.value)
网友评论