python的多线程基础设施

2024-05-16 02:08

本文主要是介绍python的多线程基础设施,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

当我们在使用线程时,存在以下基本的多线程编程的概念:

  • lock:多个线程访问临界资源时,为满足线程安全必须保证访问临界资源的代码同一时刻仅有一个线程执行。
  • condition:传递消息的工具。线程中的条件,不满足条件就wait,获得条件就执行。
  • wait():在条件实例中可用的wait()。
  • notify() / notifyAll():在条件实例中可用的notify()通知一个其他等待的线程或其他所有线程,看当前线程对临界资源状态的改变是否与所有线程有关,一般只需要通知一个其他线程即可。

python提供的多线程基础设施与其他语言的类似,都是在上述线程环境下的实现。下面是多线程实现的生产者消费者模型。

1、锁的使用

from threading import Thread, Lock
import time
import randomqueue = []
lock = Lock()class ProducerThread(Thread):def run(self):nums = range(5)while True:num = random.choice(nums)lock.acquire()queue.append(num)print "Produced", num lock.release()time.sleep(random.random())class ConsumerThread(Thread):def run(self):while True:lock.acquire()if not queue:print "Nothing in queue, but consumer will try to consume"num = queue.pop(0)print "Consumed", num lock.release()time.sleep(random.random())ProducerThread().start()
ConsumerThread().start()

lock提供的release和lock方法将对临界资源queue的访问代码进行了保护,使得不会存在同时访问临界资源的问题。但是,仅仅使用锁会出现问题,因为多个线程之间需要传递消息,(注意,传递数据使用全局变量临界资源就可以,但传递消息必须要新的工具),需要使用线程传递消息的工具condition来实现。

2、传递消息

python的多线程传递消息机制condition内含了lock,其acquire()和release()方法在内部调用了lock的acquire()和release()。所以在python中可以用condiction实例取代lock实例,但lock的行为不会改变。

from threading import Thread, Condition
import random
import timequeue = []
MAX_NUM = 10
queue_avalible = Condition()class Producer(Thread):def run(self):nums = range(MAX_NUM)while True:num = random.choice(nums)queue_avalible.acquire()if len(queue) == MAX_NUM:print "queue is full, waiting for consuming"queue_avalible.wait()queue.append(num)print "Produced ", numqueue_avalible.notify()queue_avalible.release()class Consumer(Thread):def run(self):nums = range(MAX_NUM)while True:queue_avalible.acquire()if len(queue) == 0:print "queue is empty, waiting for producing"queue_avalible.wait()num = queue.pop(0)print "Consumed ", numqueue_avalible.notify()queue_avalible.release()Producer().start()
Consumer().start()

上述使用的是Condition内部自带的lock来进行加锁解锁,但是这样有一个需要注意的问题,调用notify的时候,其他等待的线程并不能马上运行,因为使用的是同一个queue_avalible,当前调用notify之后再调用release之后其他等待线程才能运行。下面是python文档的原文:

Note: the notify() and notifyAll() methods don’t release the lock; this means that the thread or threads awakened will not return from their wait() call immediately, but only when the thread that called notify() or notifyAll() finally relinquishes ownership of the lock.
An awakened thread does not actually return from its wait() call until it can reacquire the lock. Since notify() does not release the lock, its caller should.

3、Queue封装

python中的Queue模块对多线程操作的队列进行了封装,非常方便的使用它能快速构建程序。

The Queue module implements multi-producer, multi-consumer queues. It is especially useful in threaded programming when information must be exchanged safely between multiple threads. The Queue class in this module implements all the required locking semantics.

支持如下三种队列:

  • class Queue.Queue(maxsize=0)
    FIFO队列类。 maxsize 是最大长度,达到上限之后调用put操作会被阻塞。小于等于0的maxsize将是无限大的队列。
  • class Queue.LifoQueue(maxsize=0)
    LIFO队列类。 maxsize 是最大长度,达到上限之后调用put操作会被阻塞。小于等于0的maxsize将是无限大的队列。
  • class Queue.PriorityQueue(maxsize=0)
    优先队列类。 maxsize 是最大长度,达到上限之后调用put操作会被阻塞。小于等于0的maxsize将是无限大的队列。

另外提供两种异常:
Queue.Empty
当队列为空是,调用了non-blocking get() (or get_nowait()) 函数时发生
- Queue.Full
当队列满之后,调用了 non-blocking put() (or put_nowait()) 函数时发生

提供的方法如下:
- Queue.qsize():返回队列大小
- Queue.empty()
- Queue.full()
- Queue.get([block[, timeout]]):获取一个值,如果block为true并且timeout为None,就会在队列为空时阻塞只到有元素;如果timeout为正整数,将会最多阻塞设置的时间,然后raises Empty exception。如果block为False,那么直接在有元素时返回该元素,否则直接抛出Empty异常。
- Queue.get_nowait():相当于get(false)
- Queue.put(item[, block[, timeout]]):插入一个值,如果block为true并且timeout为None,就会在队列满了之后阻塞只到有空闲位置;如果timeout为正整数,将会最多阻塞设置的时间,然后raises Full exception。如果block为False,那么直接在有空闲位置时插入,否则直接抛出Full异常。
- Queue.put_nowait(item):相当于put(item, false)
- Queue.task_done():检查后台线程是否完成
- Queue.join():等待后台线程完成

这篇关于python的多线程基础设施的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/993571

相关文章

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

Python中win32包的安装及常见用途介绍

《Python中win32包的安装及常见用途介绍》在Windows环境下,PythonWin32模块通常随Python安装包一起安装,:本文主要介绍Python中win32包的安装及常见用途的相关... 目录前言主要组件安装方法常见用途1. 操作Windows注册表2. 操作Windows服务3. 窗口操作

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

python常用的正则表达式及作用

《python常用的正则表达式及作用》正则表达式是处理字符串的强大工具,Python通过re模块提供正则表达式支持,本文给大家介绍python常用的正则表达式及作用详解,感兴趣的朋友跟随小编一起看看吧... 目录python常用正则表达式及作用基本匹配模式常用正则表达式示例常用量词边界匹配分组和捕获常用re

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

python删除xml中的w:ascii属性的步骤

《python删除xml中的w:ascii属性的步骤》使用xml.etree.ElementTree删除WordXML中w:ascii属性,需注册命名空间并定位rFonts元素,通过del操作删除属... 可以使用python的XML.etree.ElementTree模块通过以下步骤删除XML中的w:as

使用Python绘制3D堆叠条形图全解析

《使用Python绘制3D堆叠条形图全解析》在数据可视化的工具箱里,3D图表总能带来眼前一亮的效果,本文就来和大家聊聊如何使用Python实现绘制3D堆叠条形图,感兴趣的小伙伴可以了解下... 目录为什么选择 3D 堆叠条形图代码实现:从数据到 3D 世界的搭建核心代码逐行解析细节优化应用场景:3D 堆叠图

深度解析Python装饰器常见用法与进阶技巧

《深度解析Python装饰器常见用法与进阶技巧》Python装饰器(Decorator)是提升代码可读性与复用性的强大工具,本文将深入解析Python装饰器的原理,常见用法,进阶技巧与最佳实践,希望可... 目录装饰器的基本原理函数装饰器的常见用法带参数的装饰器类装饰器与方法装饰器装饰器的嵌套与组合进阶技巧

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到