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 中也存在类似的发布和订阅机制功能,在后面博客中再介绍

相关推荐
alphaTao4 分钟前
LeetCode 每日一题 2026/9/21-2026/9/27
python·算法·leetcode
计算机源码社35 分钟前
【27届大数据毕设】基于Spark的AI艺术创作者价值评估与市场趋势预测研究 基于Python与Spark的AI生成艺术受众画像及异常热度识别可视化平台
大数据·人工智能·hadoop·python·spark·毕业设计·课程设计
huisheng_qaq2 小时前
【Python基础篇-04】深入理解python的函数、参数与作用域
python·ai·函数·参数作用域
宸津-代码粉碎机7 小时前
OpenAI 连夜迎战 Grok Bot 和 Muse:AI 智能体从 “会聊天” 到 “能办事”,现在入场还来得及吗
java·大数据·人工智能·分布式·python
Y3815326627 小时前
SERP API 计费口径:credits_charged、执行失败扣费与退款边界
python·搜索引擎
蒸鱼Yuzheng9 小时前
设备端性能工件可靠导出:断点续传、哈希、manifest 与失败恢复
android·自动化测试·python·adb·数据完整性
圆圆讲门店10 小时前
挑选同城获客服务机构时需要考量的核心因素都有哪些?
大数据·网络·人工智能·python
傻啦嘿哟10 小时前
Python的默认参数把我坑惨了,原来写[]和写None的区别这么大
开发语言·python·机器学习
微小冷10 小时前
Python凸优化cvxpy初步
python·机器人·凸优化·数学规划·cvxpy
在世修行10 小时前
干货:显式映射 vs 自动判据
python·插件