python线程通信

news2024/11/6 9:56:48

在现实生活中,如果一个人团队正在共同完成任务,那么他们之间应该有通信,以便正确完成任务。 同样的比喻也适用于线程。 在编程中,要减少处理器的理想时间,我们创建了多个线程,并为每个线程分配不同的子任务。 因此,必须有一个通信设施,他们应该互相沟通交流,以同步的方式完成工作。
考虑以下与线程通信相关的重要问题 -

  • 没有性能增益 - 如果无法在线程和进程之间实现适当的通信,那么并发性和并行性的性能收益是没有用的。
  • 完成任务 - 如果线程之间没有适当的相互通信机制,分配的任务将无法正常完成。
  • 比进程间通信更高效 - 线程间通信比进程间通信更高效且更易于使用,因为进程内的所有线程共享相同的地址空间,并且不需要使用共享内存。

线程安全通信的Python数据结构

多线程代码出现了将信息从一个线程传递到另一个线程的问题。 标准的通信原语不能解决这个问题。 因此,需要实现我们自己的组合对象,以便在线程之间共享对象以使通信线程安全。 以下是一些数据结构,它们在进行一些更改后提供线程安全通信 -

  1. Set
    为了以线程安全的方式使用set数据结构,需要扩展set类来实现我们自己的锁定机制。
    以下是一个扩展类的Python示例 -
class extend_class(set):
   def __init__(self, *args, **kwargs):
      self._lock = Lock()
      super(extend_class, self).__init__(*args, **kwargs)

   def add(self, elem):
      self._lock.acquire()
      try:
      super(extend_class, self).add(elem)
      finally:
      self._lock.release()

   def delete(self, elem):
      self._lock.acquire()
      try:
      super(extend_class, self).delete(elem)
      finally:
      self._lock.release()

在上面的例子中,定义了一个名为extend_class的类对象,它继承自Python集合类。 在这个类的构造函数中创建一个锁对象。 现在有两个函数 - add()和delete()。 这些函数被定义并且是线程安全的。 它们都依赖于超类功能以及一个键异常。
修饰器
这是线程安全通信的另一个关键方法是使用装饰器。
示例
考虑一个Python示例,展示如何使用装饰器和mminus;

def lock_decorator(method):

   def new_deco_method(self, *args, **kwargs):
      with self._lock:
         return method(self, *args, **kwargs)
return new_deco_method

class Decorator_class(set):
   def __init__(self, *args, **kwargs):
      self._lock = Lock()
      super(Decorator_class, self).__init__(*args, **kwargs)

   @lock_decorator
   def add(self, *args, **kwargs):
      return super(Decorator_class, self).add(elem)
   @lock_decorator
   def delete(self, *args, **kwargs):
      return super(Decorator_class, self).delete(elem)

在上面的例子中,已经定义了一个名为lock_decorator的装饰器方法,该方法从Python方法类继承。 然后在这个类的构造函数中创建一个锁对象。 现在有两个函数 - add()和delete()。 这些函数被定义并且是线程安全的。 他们都依靠超类功能和一个键异常。

  1. list

列表数据结构对于临时内存存储而言是线程安全,快速以及简单的结构。在Cpython中,GIL可以防止对它们的并发访问。当我们知道列表是线程安全的,但是数据在哪里呢。实际上,该列表的数据不受保护。例如,如果另一个线程试图做同样的事情,则L.append(x)不保证能够返回预期的结果。这是因为尽管append()是一个原子操作并且是线程安全的,但另一个线程试图以并发方式修改列表数据,因此可以看到竞争条件对输出的副作用。

为了解决这类问题并安全地修改数据,我们必须实现一个适当的锁定机制,这进一步确保多个线程不会潜在竞争条件。为了实现适当的锁定机制,可以像前面的例子那样扩展这个类。
列表上的其他一些原子操作如下所示 -

L.append(x)
L1.extend(L2)
x = L[i]
x = L.pop()
L1[i:j] = L2
L.sort()
x = y
x.field = y
D[x] = y
D1.update(D2)
D.keys()

这里 -

  • L,L1,L2都是列表
  • D,D1,D2是字典
  • x,y是对象i,j是整数’
  1. 队列
    如果清单数据不受保护,我们可能不得不面对后果。 可能会得到或删除错误的数据项,竞争条件。 这就是为什么建议使用队列数据结构的原因。 一个真实世界的排队示例可以是单车道单向道路,车辆首先进入,首先退出。 售票窗口和公共汽车站的队列中可以看到更多真实世界的例子。

在这里插入图片描述

队列是默认的线程安全数据结构,我们不必担心实现复杂的锁定机制。 Python提供了应用程序中使用不同类型队列的模块。
队列类型
在本节中,我们将获得关于不同类型的队列的信息。 Python提供了三种从queue模块使用的队列选项 -

  • 正常队列(FIFO,先进先出)
  • 后进先出,后进先出
  • 优先级

我们将在随后的章节中了解不同的队列。
正常队列(FIFO,先进先出)
它是Python提供的最常用的队列实现。 在这种先排队的机制中,首先得到服务。 FIFO也被称为正常队列。 FIFO队列可以表示如下 -

在这里插入图片描述

FIFO队列的Python实现
在python中,FIFO队列可以用单线程和多线程来实现。
具有单线程的FIFO队列
要实现单线程的FIFO队列,Queue类将实现一个基本的先进先出容器。 使用put()将元素添加到序列的一个“结尾”,并使用get()从另一端移除元素。
示例
以下是用单线程实现FIFO队列的Python程序 -

import queue

q = queue.Queue()

for i in range(8):
   q.put("item-" + str(i))

while not q.empty():
   print (q.get(), end = " ")

执行上面示例代码,得到以下结果 -

item-0 item-1 item-2 item-3 item-4 item-5 item-6 item-7

输出结果显示上面的程序使用单个线程来说明这些元素将按照它们插入的顺序从队列中移除。
具有多个线程的FIFO队列
为了实现多线程的FIFO,需要从queue模块扩展来定义myqueue()函数。 get()和put()方法的工作方式与上面讨论的一样,只用单线程实现FIFO队列。 然后为了使它成为多线程,我们需要声明和实例化线程。 这些线程将以FIFO方式使用队列。
示例
以下是用于实现具有多个线程的FIFO队列的Python程序

import threading
import queue
import random
import time
def myqueue(queue):
   while not queue.empty():
   item = queue.get()
   if item is None:
   break
   print("{} removed {} from the queue".format(threading.current_thread(), item))
   queue.task_done()
   time.sleep(2)
q = queue.Queue()
for i in range(5):
   q.put(i)
threads = []
for i in range(4):
   thread = threading.Thread(target=myqueue, args=(q,))
   thread.start()
   threads.append(thread)
for thread in threads:
   thread.join()

执行上面示例代码,得到以下结果

<Thread(Thread-3654, started 5044)> removed 0 from the queue
<Thread(Thread-3655, started 3144)> removed 1 from the queue
<Thread(Thread-3656, started 6996)> removed 2 from the queue
<Thread(Thread-3657, started 2672)> removed 3 from the queue
<Thread(Thread-3654, started 5044)> removed 4 from the queue
  1. LIFO,后进先出队列
    队列使用与FIFO(先进先出)队列完全相反的类比。 在这个队列机制中,最后一个将首先获得服务。 这与实现堆栈数据结构相似。 LIFO队列在实施深度优先搜索时非常有用,如人工智能算法。
    LIFO队列的Python实现
    在python中,LIFO队列可以用单线程和多线程来实现。
    单线程的LIFO队列
    要用单线程实现LIFO队列,Queue类将使用结构Queue.LifoQueue来实现基本的后进先出容器。 现在,在调用put()时,将元素添加到容器的头部,并使用get()从头部移除。
    示例
    以下是用单线程实现LIFO队列的Python程序 -
import queue

q = queue.LifoQueue()

for i in range(8):
   q.put("item-" + str(i))

while not q.empty():
   print (q.get(), end=" ")

执行上面示例代码,得到以下结果 -

item-7 item-6 item-5 item-4 item-3 item-2 item-1 item-0

输出显示上述程序使用单个线程来说明元素将以插入的相反顺序从队列中移除。
带有多个线程的LIFO队列
这个实现与使用多线程实现FIFO队列相似。 唯一的区别是需要使用Queue类,该类将使用结构Queue.LifoQueue来实现基本的后进先出容器。
示例
以下是用于实现具有多个线程的LIFO队列的Python程序 -

import threading
import queue
import random
import time
def myqueue(queue):
   while not queue.empty():
      item = queue.get()
      if item is None:
      break
      print("{} removed {} from the queue".format(threading.current_thread(), item))
      queue.task_done()
      time.sleep(2)
q = queue.LifoQueue()
for i in range(5):
   q.put(i)
threads = []
for i in range(4):
   thread = threading.Thread(target=myqueue, args=(q,))
   thread.start()
   threads.append(thread)
for thread in threads:
   thread.join()

执行上面示例代码,得到以下结果 -

<Thread(Thread-3882, started 4928)> removed 4 from the queue
<Thread(Thread-3883, started 4364)> removed 3 from the queue
<Thread(Thread-3884, started 6908)> removed 2 from the queue
<Thread(Thread-3885, started 3584)> removed 1 from the queue
<Thread(Thread-3882, started 4928)> removed 0 from the queue

优先队列
在FIFO和LIFO队列中,项目顺序与插入顺序有关。 但是,有很多情况下优先级比插入顺序更重要。 让我们考虑一个真实世界的例子。 假设机场的安保人员正在检查不同类别的人员。 VVIP的人员,航空公司工作人员,海关人员,类别可能会优先检查,而不是像到平民那样根据到达情况进行检查。
需要考虑优先队列的另一个重要方面是如何开发任务调度器。 一种常见的设计是在队列中优先处理最具代理性的任务。 该数据结构可用于根据队列的优先级值从队列中提取项目。
优先队列的Python实现
在python中,优先级队列可以用单线程和多线程来实现。
单线程优先队列
要实现单线程优先队列,Queue类将使用结构Queue.PriorityQueue在优先级容器上实现任务。 现在,在调用put()时,元素将添加一个值,其中最低值将具有最高优先级,并因此使用get()首先检索。
示例
考虑下面的Python程序来实现单线程的优先级队列 -

import queue as Q
p_queue = Q.PriorityQueue()

p_queue.put((2, 'Urgent'))
p_queue.put((1, 'Most Urgent'))
p_queue.put((10, 'Nothing important'))
prio_queue.put((5, 'Important'))

while not p_queue.empty():
   item = p_queue.get()
   print('%s - %s' % item)

执行上面示例代码,得到以下结果 -

1 – Most Urgent
2 - Urgent
5 - Important
10 – Nothing important

在上面的输出中,可以看到队列已经存储了基于优先级的项目 - 较少的值具有高优先级。
具有多线程的优先队列
该实现类似于具有多个线程的FIFO和LIFO队列的实现。 唯一的区别是需要使用Queue类通过使用结构Queue.PriorityQueue来初始化优先级。 另一个区别是队列的生成方式。 在下面给出的例子中,它将生成两个相同的数据集。
示例
以下Python程序有助于实现具有多个线程的优先级队列 -

import threading
import queue
import random
import time
def myqueue(queue):
   while not queue.empty():
      item = queue.get()
      if item is None:
      break
      print("{} removed {} from the queue".format(threading.current_thread(), item))
      queue.task_done()
      time.sleep(1)
q = queue.PriorityQueue()
for i in range(5):
   q.put(i,1)

for i in range(5):
   q.put(i,1)

threads = []
for i in range(2):
   thread = threading.Thread(target=myqueue, args=(q,))
   thread.start()
   threads.append(thread)
for thread in threads:
   thread.join()

执行上面示例代码,得到以下结果 -

<Thread(Thread-4939, started 2420)> removed 0 from the queue
<Thread(Thread-4940, started 3284)> removed 0 from the queue
<Thread(Thread-4939, started 2420)> removed 1 from the queue
<Thread(Thread-4940, started 3284)> removed 1 from the queue
<Thread(Thread-4939, started 2420)> removed 2 from the queue
<Thread(Thread-4940, started 3284)> removed 2 from the queue
<Thread(Thread-4939, started 2420)> removed 3 from the queue
<Thread(Thread-4940, started 3284)> removed 3 from the queue
<Thread(Thread-4939, started 2420)> removed 4 from the queue
<Thread(Thread-4940, started 3284)> removed 4 from the queue

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/374629.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线上监控诊断神器arthas

目录 什么是arthas 常用命令列表 1、dashboard仪表盘 2、heapdump dumpJAVA堆栈快照 3、jvm 4、thread 5、memory 官方文档 安装使用 1、云安装arthas 2、获取需要监控进程ID 3、运行arthas 4、进入仪表盘 5、其他命令使用查看官方文档 什么是arthas arthas是阿…

【自然语言处理】BERT GPT

BERT & GPT近年来&#xff0c;随着大规模预训练语言模型的发展&#xff0c;自然语言处理领域发生了巨大变革。BERT 和 GPT 是其中最流行且最有影响力的两种模型。在本篇博客中&#xff0c;我们将讨论 BERT 和 GPT 之间的区别以及它们的演变过程。 1.起源 201820182018 年&a…

2023软件测试现状,点工如何破局成为卷王····

近几年来的特殊情况&#xff0c;综合过去的大形势变化&#xff0c;所有行业都会自下而上的进行一轮技术“大清洗”&#xff0c;技术停滞不前的“点工”或将被逐步取代。 软件测试现状 测试行业在十几年间发生了翻天覆地的变化&#xff0c;从早期站在风口上的快速发展&#xf…

【mybatis】 01- mybatis快速入门

数据库创建(注意&#xff1a;最好先创建好数据库设置utf8再进行表创建) create database mybatis; use mybatis;drop table if exists tb_user;create table tb_user(id int primary key auto_increment,username varchar(20),password varchar(20),gender char(1),addr varch…

【数据结构】初识二叉树(二叉树的入门知识)

初识二叉树一、树概念及结构1、树的概念2、树的相关概念3、树的表示4、树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09;二、二叉树概念及结构1、概念2、特殊的二叉树3、二叉树的性质4、二叉树的存储结构三、结语一、树概念及结构 1、树的概念 树是一种非线…

【win10网络重置后,网络适配器消失或者不能使用】

注&#xff1a;此文章为重新整理的版本&#xff0c;旧版本&#xff1a;https://blog.csdn.net/Viwise/article/details/123263847?spm1001.2014.3001.5502 目录 一、问题描述 【总结】 【过程】 二、方法 1、针对设备问题代码为56的解决方法&#xff1a;安装CCleaner &am…

建模算法整理

优化 改进的蝙蝠算法 2022 E 2218144 使用背景&#xff1a;将每年砍伐树木比例定义为n&#xff0c;每年树木种植比例定义为m&#xff0c;设置一系列指标以及指标的加权计算方法&#xff08;即函数F(X)的设定&#xff09;&#xff0c;寻找最优的n,m。 蝙蝠算法主要用于目标函数…

算法leetcode|38. 外观数列(多语言实现)

文章目录38. 外观数列&#xff1a;样例 1&#xff1a;样例 2&#xff1a;提示&#xff1a;分析&#xff1a;题解&#xff1a;rustgocpythonjava38. 外观数列&#xff1a; 给定一个正整数 n &#xff0c;输出外观数列的第 n 项。 「外观数列」是一个整数序列&#xff0c;从数字…

【C++】map和set的封装(红黑树)

map和set的封装一、介绍二、stl源码剖析三、仿函数获取数值四、红黑树的迭代器五、map的[]5.1 普通迭代器转const迭代器六、set源码七、map源码八、红黑树源码一、介绍 首先要知道map和set的底层都是用红黑树实现的 【数据结构】红黑树 set只需要一个key&#xff0c;但是map既…

分布式-分布式消息笔记

消息队列应用场景 消息队列 消息队列是进程之间的一种很重要的通信机制。参与消息传递的双方称为生产者和消费者&#xff0c;生产者和消费者可以只有一个实例&#xff0c;也可以集群部署。 消息体是参与生产和消费两方传递的数据&#xff0c;消息格式既可以是简单的字符串&am…

MYSQL安装部署 - Linux 本地安装及卸载

声明 &#xff1a;# 此次我们安装的 MYSQL 版本是 8.0.32 版本我们本次安装 MYSQL 总共要介绍 四种方式# 仓库安装# 本地安装# 容器安装# 源码安装我们本篇介绍的是 本地安装 我们还是去官网下载 &#xff1a;我们就是找着 .bundle.tar 这个包&#xff0c;里面就包含了所有 mys…

功率信号源有什么作用和功能呢

功率信号源是指集信号发生器与功率放大器为一体的电子测量仪器&#xff0c;它具有高电压、大功率的特点&#xff0c;在电子实验室中能够帮助用来驱动压电陶瓷、换能器以及电磁线圈等&#xff0c;可以有效的帮助电子工程师解决驱动负载和放大功率的问题。功率信号源和功率放大器…

过滤器,监听器,拦截器的原理与在Servlet和Spring的应用

在Java Web的开发中&#xff0c;最原始和初期的学习都是从Servlet开始的&#xff0c;Servlet是Java最为耀眼的技术&#xff0c;也是Java EE的技术变革。目前大火主流的框架spring boot也的spring mvc部分也是基于拓展servlet完成的。回到之前的文章spring 实现了对servlet的封装…

SQL语句大全(详解)

SQL前言1 DDL1.1 显示所包含的数据库1.2 创建数据库1.3 删除数据库1.4 使用数据库1.4.1 创建表1.4.2 查看表的结构1.4.3 查看当前数据库下的所有表1.4.4 基础的增删改查1.4.4.1 删除表1.4.4.2 添加列1.4.4.3 修改表名1.4.4.4 修改数据类型1.4.4.5 修改列名和数据类型2 DML2.1 给…

http协议简介

http 1.简介 超文本传输协议&#xff08;HTTP&#xff0c;HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处…

Python实现GWO智能灰狼优化算法优化循环神经网络分类模型(LSTM分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。1.项目背景灰狼优化算法(GWO)&#xff0c;由澳大利亚格里菲斯大学学者 Mirjalili 等人于2014年提出来的一种群智能优…

【玩转c++】git的安装和使用以及可视化处理

本期主题&#xff1a;git的安装和使用&#xff08;windows环境&#xff09;博客主页&#xff1a;小峰同学分享小编的在Linux中学习到的知识和遇到的问题 小编的能力有限&#xff0c;出现错误希望大家不吝赐1.两个工具介绍第一个工具git&#xff0c;链接gitee或者github等代码托…

B端产品经理如何做好客户访谈?

用户访谈的价值我们在做用户研究的时候&#xff0c;经常会采用问卷调查和数据分析等定量的研究方法&#xff0c;从中我们可以搜集很多有价值的数据。但是&#xff0c;这些数据往往只停留在表层&#xff0c;没有办法基于用户的场景了解用户行为动机及诉求&#xff0c;很难找到用…

MySql的安装

版本选择 MySql目前使用最稳定的版本为5.7系列版本,尝鲜可以直接去官网链接整最新版本哦 本文使用8.0.32版本,注意这里看一下电脑位数,现在个人电脑一般都是64bit 点击223.6M那个压缩包开始下载,下面那个压缩包包含了测试相关内容一般是不需要的 这里有时会提示要你登录账户…

【REACT-@reduxjs/toolkit+react-redux+redux-persist状态管理】

REACT-reduxjs/toolkitreact-reduxredux-persist状态管理1. 依赖包安装2. 目录结构3. 修改Index.js4. createSlice&#xff08;&#xff09;4.1 action处理4.1.1 创建collapsedSlice4.1.2 使用collapsedSlice4.2 异步action处理4.2.1 使用redux-thunk方式处理异步4.2.1.1 创建a…