前文:

signal-slot:python版本的多进程通信的信号与槽机制(编程模式)的库(library) —— 强化学习ppo算法库sample-factory的多进程包装器,实现类似Qt的多进程编程模式(信号与槽机制) —— python3.12版本下成功通过测试

信号与槽机制,是C++的Qt框架提出的一种并行编程模式,实际上是对原生的并行编程模式进行了一定的封装和包装,是wrap操作。

编程语言原生的并行编程模式,一般是创建多个子进程,每个子进程均拥有一个以上的通信队列,各个进程间的通信通过进程队列进行;如果一个进程想要调用另一个进程中的某个函数,并传递给其参数,那么就在通信队列中传入需要调用对方进程的具体函数名和参数,然后对方进程从队列中取出该函数名和具体参数,并按此执行,这就是不使用Qt信号与槽机制包装之前的原生并行编程通信的模式。但是使用原生的并行通信编程模式其编码比较繁琐,尤其对于一些通信场景比较复杂的情况,往往会因为过多的编码导致逻辑混乱而不利于维护,因此Qt框架提出了信号与槽机制编码模式。

简单的说,也就是在不同的对象中实现了signal函数和slot函数,在不同对象实例化后将信号发送方的signal函数注册到信号接收方的slot函数上,这个操作一般使用connection函数,完成了该函数操作实际上就是完成了signal函数对应的接收方的队列的注册,也就是说在发送方调用signal函数时会自动把自身的函数名和需要调用的对方函数名以及参数指定到接收方的队列上。

在这个项目中对发送方和接收方都需要设置循环事件对象,每个循环事件都相当于一个进程,这个进程会不断的循环执行取队列操作,并根据队列中取出的被调用函数及参数进行调用。需要注意的是,该项目的实现是需要在主进程中实现所有声明的,也就是将signal函数注册到slot函数上是在主进程中实现的,也就是connection函数操作只能在主进程中实现。虽然项目实现signal和slot的注册,并且connection可以随时进行,但是所有的声明和connection操作必须在主进程中执行。

每个带有signal和slot函数的对象都必须绑定到一个EventLoop事件上,不同的EventLoop事件运行在不同的进程上,实际上由于EventLoop事件是一个单独的进程,而所有的signal、slot、connection声明都是在主进程中进行的,因此子进程的EventLoop事件启动后会将主进程中与其绑定的带有signal和slot函数的对象copy到子进程中(spawn方式的子进程生成方式,会将主进程中的一切对象全部copy到子进程中,因为信号与槽机制中对被调用对象的标识是使用身份ID字符串的,因此即使在主进程中进行的注册声明,在copy到子进程中依旧可以毫无影响的同样进行调用,只不过具体执行时是在子进程中)。

也正因为该项目的这种实现方式(子进程启动后copy父进程中的所有对象),那么其实任意一个运行在子进程中的对象在主进程中都是有着一个同样的影子对象的,因此我们在主进程中调用一个绑定在子进程中的对象的signal函数时其实并不是在调用运行在子进程中的对象,而是调用其在主进程中的影子对象,因此可以认为所有在主进程中完成connection的signal函数并且其信号发射操作(emit函数)也是在主进程中进行的,那么气emit操作就是在主进程中进行的;同时由于子进程的copy默认操作,那么在子进程中对绑定到子进程上的对象进行emit操作其实是在子进程中进行的;因此总的来说,signal和slot的connection操作必须在主进程中进行声明和执行,但是emit操作在哪里执行是需要看其被调用的对象绑定到哪个进程上的。

信号与槽机制的核心原理,就是进程和进程间通信时通过队列实现的,一个进程中的对象如果调用另一个进程中的某个对象的函数,其实就是把被调用对象的ID字符串和被调用函数的ID字符串以及参数一并通过队列发送给被调用的进程。

需要注意,signal-slot库通过在主进程中实现对signal和slot的connection的声明和注册,其实就是将slot函数的对象ID字符串及通信队列和函数ID字符串绑定给signal函数,这样在signal函数进行emit操作时其实质就是将信息message连同slot函数的对象ID字符串和函数ID字符串发送给slot函数的对象的通信队列。由于每个slot函数所属对象的队列都是在主进程中声明并绑定在各自的对象内的,而EventLoop都是在所有声明完成后在生成子进程时自动copy父进程的所有对象到子进程中的,因此所有的队列都是在主进程和子进程之间的,并没有子进程之间的队列,由于这种声明注册、绑定、子进程copy方式实现的信号与槽机制,只将每个EventLoop的队列暴露给自身,难以实现子进程之间的通信。

PS. 可以说,这个项目的实现比较复杂,逻辑也比较混乱,虽然可以实现作者的设定目标,但是这个逻辑搞的如此混乱也是难以继续维护的,可以说这个项目就是论文代码的副产品,并不具有延续性。

项目作者给出的待完善的功能:

It is currently impossible to connect a slot to a signal if emitter and receiver objects belong to event loops already running in different processes (although it should be possible to implement this feature). Connect signals to slots during system initialization.

简单的说,就是需要先connection设置好以后才可以start,如果start了以后再connection就不会有限,这个原因就是上面刚才说的这个子进程启动的copy操作,如果子进程启动以后自然是不会再copy父进程中后生成的对象的设置了。

(续)signal-slot:python版本的多进程通信的信号与槽机制(编程模式)的库(library) —— 强化学习ppo算法库sample-factory的多进程包装器,实现类似Qt的多进程编程模式(信号与槽机制) —— python3.12版本下成功通过测试的更多相关文章

  1. Python中根据库包名学习使用该库包

    目录 Python库包模块 import 语句 from-import 语句 搜索路径 PYTHONPATH 变量 命名空间和作用域 查看模块中所有变量和函数,以及查看具体函数的用法 globals( ...

  2. python类库32[多进程通信Queue+Pipe+Value+Array]

    多进程通信 queue和pipe的区别: pipe用来在两个进程间通信.queue用来在多个进程间实现通信. 此两种方法为所有系统多进程通信的基本方法,几乎所有的语言都支持此两种方法. 1)Queue ...

  3. QT写hello world 以及信号槽机制

    QT是一个C++的库,不仅仅有GUI的库.首先写一个hello world吧.敲代码,从hello world 写起. #include<QtGui/QApplication> #incl ...

  4. 详解 Qt 线程间共享数据(使用signal/slot传递数据,线程间传递信号会立刻返回,但也可通过connect改变)

    使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的. Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容.Qt线程间共享 ...

  5. Qt信号槽的一些事 Qt::带返回值的信号发射方式

    一般来说,我们发出信号使用emit这个关键字来操作,但是会发现,emit并不算一个调用,所以它没有返回值.那么如果我们发出这个信号想获取一个返回值怎么办呢? 两个办法:1.通过出参形式返回,引用或者指 ...

  6. 使用 C++11 编写类似 QT 的信号槽——上篇

    了解 QT 的应该知道,QT 有一个信号槽 Singla-Slot 这样的东西.信号槽是 QT 的核心机制,用来替代函数指针,将不相关的对象绑定在一起,实现对象间的通信. 考虑为 Simple2D 添 ...

  7. QT窗体间传值总结之Signal&Slot

    在写程序时,难免会碰到多窗体之间进行传值的问题.依照自己的理解,我把多窗体传值的可以使用的方法归纳如下: 1.使用QT中的Signal&Slot机制进行传值: 2.使用全局变量: 3.使用pu ...

  8. QT 中 关键字讲解(emit,signal,slot)

    Qt中的类库有接近一半是从基类QObject上继承下来,信号与反应槽(signals/slot)机制就是用来在QObject类或其子类间通讯的方法.作为一种通用的处理机制,信号与反应槽非常灵活,可以携 ...

  9. Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型

    Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型 一丶互斥锁 含义: ​ ​ ​ 每个对象都对应于一个可称为" 互斥锁&qu ...

  10. 《ASP.NET MVC4 WEB编程》学习笔记------Entity Framework的Database First、Model First和Code Only三种开发模式

    作者:张博出处:http://yilin.cnblogs.com Entity Framework支持Database First.Model First和Code Only三种开发模式,各模式的开发 ...

随机推荐

  1. windows 命令行调整分辨率

    windows 命令行调整分辨率 下载:qres_v1.1 https://abcker.lanzouq.com/i1uzA1a5uo8j 解压出来,如:D:\Soft\QRes,不要使用中文名目录. ...

  2. 手把手教你搭建Docker私有仓库Harbor

    1.什么是Docker私有仓库 Docker私有仓库是用于存储和管理Docker镜像的私有存储库.Docker默认会有一个公共的仓库Docker Hub,而与Docker Hub不同,私有仓库是受限访 ...

  3. uni-app apple store 上传新版本审核被拒绝 Guideline 5.1.1

    - Legal - Privacy - Data Collection and Storage We noticed that your app requests the user's consent ...

  4. 聊一聊 Monitor.Wait 和 Pluse 的底层玩法

    一:背景 1. 讲故事 在dump分析的过程中经常会看到很多线程卡在Monitor.Wait方法上,曾经也有不少人问我为什么用 !syncblk 看不到 Monitor.Wait 上的锁信息,刚好昨天 ...

  5. Django设置、使用Cookie

    使用背景: 前端根据用户选择的模块,结合ajax实现局部刷新,进到到具体模块页面后,返回,希望保持到原来选择的模块上,这就需要保存当前选择的模块id; 尝试: 1.使用Js的设置cookie,douc ...

  6. Java解析微信获取手机号信息

    在微信中,用户手机号的获取通常是通过微信小程序的getPhoneNumber接口来实现的.这个接口允许用户在授权后,将加密的手机号数据传递给开发者.由于隐私保护,微信不会直接提供用户的明文手机号,而是 ...

  7. Linux上快速安装 RabbitMQ

    1.默认安装最新版,安装erlang apt-get install erlang 2.安装最新版 rabbitmq sudo apt-get update sudo apt-get install ...

  8. ABP框架开发实例教程-生成数据库

    因为用SQLSERVER数据库比较多,这里就以SQLSERVER2014为例,下面说一下生成步骤: 1.用VS2019打开生成的ABP框架源码的解决方案,先修改web.mvc.web.host两个项目 ...

  9. Babel 7 初探

    Babel有两大功能,转译和polyfill.转译就是把新的JS的语法,转化成旧的JS的语法.polyfill则是针对JS中新增的一些对象(Map, Set)和实例方法,这些对象和方法,在旧的浏览器中 ...

  10. springboot 整合 pagehelper

    pom.xml <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pa ...