python自学博客记录 第12章 多线程与并行(3/4)

12.2.3 线程同步
如果有多个线程共同修改或者操作同一对象或数据,就会可能发生一些意想不到的事 如:

import time
import threading

class MyThread(threading.Thread):
    def __init__(self,thread_id):
        super(MyThread,self).__init__()
        self.thread_id = thread_id

    def run(self):
        for i in range(10):
            print("Thread %d\t printing! times:%d" % (self.thread_id,i))

            time.sleep(1)

        for i in range(10):
            print("Thread %d\t printing! times: %d" % (self.thread_id,i))

def main():
    print("Main thread start")
    threads = []

    #创建线程
    for i in range(5):
        thread = MyThread(i)
        threads.append(thread)

    #启动线程
    for i in range(5):
        threads [i].start()

    #等待进程执行完毕
    for i in range(5):
        threads [i].join()

    print("Main thread finish")

if __name__ == "__main__":
    main()

这个例子每运行一次他的输出结果都是不同的。为了保证数据的正确性,我们需要将多个线程进行同步。
标准库中threading中有个Lock对象可以实现简单的线程同步

12.2.4 队列
标准库提供了一个非常有用的Queue模块、可以帮助我们自动的控制锁,保持数据同步。
Python 的 Queue 模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列 PriorityQueue。

这些队列都实现了锁原语,能够在多线程中直接使用,可以使用队列来实现线程间的同步。

Queue 模块中的常用方法:

Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.full 与 maxsize 大小对应
Queue.get([block[, timeout]])获取队列,timeout等待时间
Queue.get_nowait() 相当Queue.get(False)
Queue.put(item) 写入队列,timeout等待时间
Queue.put_nowait(item) 相当Queue.put(item, False)
Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
Queue.join() 实际上意味着等到队列为空,再执行别的操作

from queue import Queue
q = Queue()
for i in range(5):
    q.put(i)


while not q.empty():
    print(q.get())

Queue模块并不是一定要使用多线程才能使用,这个例子使用单线程演示了元素以插入顺序从队列中移除

 import time
import threading
import queue

#创建工作队列并且限制队列的最大元素是10个
work_queue = queue.Queue(maxsize=10)

#创建结果队列并且限制队列的最大元素是10个
result_queue = queue.Queue(maxsize=10)

class WorkerThredd(threading.Thread):
    def __init__(self,thread_id):
        super(WorkerThredd,self).__init__()
        self.thread_id = thread_id

    def run(self):
        while not work_queue.empty():
            #从工作队列获取数据
            work = work_queue.get()
            #模拟工作耗时3秒
            time.sleep(3)
            out = "Thread %d\t received %s" %(self.thread_id,work)
            #把队列放入结果队列
            result_queue.put(out)

def main():
    #把工作队列放入数据
    for i in range(10):
        work_queue.put("message id %d" %i)

    #开启两个工作线程
    for i in range(2):
        thread = WorkerThredd(i)
        thread.start()
    #输出十个结果
    for i in range(10):
        result = result_queue.get()
        print(result)

if __name__ == '__main__':
    main()

多线程使用Queue模块也不需要多余的锁操作,因为queue.Queue对象已经在执行方法的时候帮助我们自动调用threading.Lock来实现锁的使用,标准库queue模块不止有Queue一种队列,还有LifoQueue和PriorityQueue等功能更复杂的队列。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值