Python订阅与发布功能简介

发布-订阅(Publish-Subscribe)模式是一种消息传递模式,用于实现组件之间的松耦合通信。在这种模式中,发送者(发布者)不需要知道接收者(订阅者)的存在,反之亦然。发布者将消息发布到频道上,而订阅者可以订阅一个或多个频道以接收这些消息。这是一种常用的机制,可类比C#中事件和响应回调函数。

一. C#事件与响应回调函数

C# 事件 / 回调只能局限当前进程, 本质是内存里的函数指针列表, 只存在当前进程, 当前应用程序域, 不能跨进程、不能跨电脑、不能跨程序, 另一个exe 完全感知不到,连不上、收不到事件。如下是一个演示例子。

cs 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    public class A
    {
        public delegate void DelRun(string info);
        public event DelRun EventRun;

        public void trigger(string s)
        {
            if (EventRun != null)
                EventRun(s);
        }
    }

    public class B
    {
        private A a;

        public B()
        {
            a = new A();
        }

        private void Output(string s)
        {
            Console.WriteLine(s);
        }

        public void Blind()
        {
            a.EventRun += Output;
        }

        public void Trigger()
        {
            a.trigger("hello world");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            B b= new B();
            b.Blind();
            b.Trigger();
        }
    }
}

运行效果如下:

二. Python的发布与订阅

  1. Python还可以跨进程、跨程序、跨电脑、跨语言。如下介绍通过Redis来实现分布式,Redis是一个跑在电脑上的一个独立小程序,专门用来存数据、发消息、做中间件。官网下载地址如下:

https://github.com/tporadowski/redis/releases

下载完毕后,直接运行redis-server.exe即可

接下来,pip安装Redis

这边在Pycharm中创建两份.py文件,一份名为Publisher_1.py,用作发布功能,代码为:

python 复制代码
import redis
import json

r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)

# 发布消息1
tcp_msg1 = "hello world"
r.publish("topic1", tcp_msg1)

# 发布消息2
tcp_msg2 = "welcom"
r.publish("topic2", tcp_msg2)
print("over")

一份名为Subscriber_1.py,用作订阅功能,代码为:

python 复制代码
import redis
import json

# 连接Redis
r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)
pubsub = r.pubsub()

# 订阅主题\事件\消息
pubsub.subscribe("topic1", "topic2")
print("等待消息...")

# 监听消息
for msg in pubsub.listen():
    if msg["type"] == "message":
        topic = msg["channel"]
        data = msg["data"]
        print(topic + ":" + data)

执行后效果如下(先执行Subscriber_1.py,再执行Publisher_1.py):

  1. 接下来用第三方库pyPubSub, 此仅支持进程内,不支持跨进程

首先先用pip安装该库

然后用Pycharm创建Test_Pypubsub.py,里面代码为:

python 复制代码
from pubsub import pub


# 订阅者回调函数
def listener1(msg):
    print(msg)


def listener2(msg):
    print(msg)


# 订阅主题
pub.subscribe(listener1, "topic1")
pub.subscribe(listener2, "topic2")

# 发布消息
pub.sendMessage("topic1", msg="Hello PyPubSub1")
pub.sendMessage("topic1", msg="Hello PyPubSub2")

运行后效果如下:

  1. 不调用第三方库,自己手写(类似一个简单的两点距离计算,不用调opencv的库)
python 复制代码
from collections import defaultdict
import threading

class LocalPubSub:
    def __init__(self):
        #  key:主题,value:订阅者回调函数列表
        self.subscribers = defaultdict(list)
        self.lock = threading.Lock()

    # 订阅主题
    def subscribe(self, topic, callback):
        with self.lock:
            self.subscribers[topic].append(callback)

    # 发布消息
    def publish(self, topic, *args, **kwargs):
        with self.lock:
            callbacks = self.subscribers[topic].copy()
        # 异步通知所有订阅者
        for callback in callbacks:
            threading.Thread(target=callback, args=args, kwargs=kwargs).start()

# 测试
if __name__ == "__main__":
    pubsub = LocalPubSub()
    # 订阅者1
    def on_news(msg):
        print(f"订阅者1 收到:{msg}")
    # 订阅者2
    def on_news2(msg):
        print(f"订阅者2 收到:{msg}")

    pubsub.subscribe("news", on_news)
    pubsub.subscribe("news", on_news2)
    # 发布消息
    pubsub.publish("news", "Python Pub/Sub 测试消息")

执行效果如下:

可看到不管哪种方式,subscribe要注明收到消息后,要干什么活(对应可以是封装的函数或执行语句)。

注: ROS2 中也存在类似的发布和订阅机制功能,在后面博客中再介绍

相关推荐
用户6757049885022 小时前
Python 装饰器很难?那是你没看到这篇文章!
后端·python
码界筑梦坊2 小时前
124-基于Python的航空旅客满意度数据可视化分析系统
开发语言·python·信息可视化·数据分析·flask·毕业设计
星越华夏2 小时前
PPTX判断包含图表id
python·pandas
梦想不只是梦与想2 小时前
Python 中的流程控制语句
python·流程控制·循环·条件判断·if
dinl_vin2 小时前
FastAPI 系列(一)· 初体验——从 Spring Boot 工程师视角认识 FastAPI
后端·python·fastapi
AI玫瑰助手2 小时前
Python流程控制:pass语句的作用与使用场景
开发语言·python·信息可视化
Metaphor6922 小时前
使用 Python 设置 Word 文档文本的颜色
python·word
肥胖小羊3 小时前
基于状态机的客户生命周期流转与自动化触达引擎实现
开发语言·python