Python threading — 管理单个进程里的并行操作

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)

你可能感兴趣的:(Python threading — 管理单个进程里的并行操作)