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

相关推荐
love530love9 小时前
LiveTalking 数字人项目 Windows 部署完全指南(EPGF 架构)
人工智能·windows·python·架构·livetalking·epgf
遇事不決洛必達9 小时前
【Python基础】GIL 锁是什么及其对爬虫的影响
爬虫·python·线程·进程·gil锁
CryptoPP10 小时前
快速对接东京证券交易所API数据:实战指南与代码示例
开发语言·人工智能·windows·python·信息可视化·区块链
探物 AI11 小时前
把 MambaOut 塞进 YOLOv11:会有什么样的反应
python·yolo·计算机视觉
如竟没有火炬11 小时前
最大矩阵——单调栈
数据结构·python·线性代数·算法·leetcode·矩阵
阳区欠11 小时前
【LangChain】LLM基础介绍
开发语言·python·langchain
Cosolar11 小时前
保姆级 CrewAI 教程:从零构建多智能体协作系统
人工智能·python·架构
GDAL11 小时前
使用 uv 管理 Python 版本
python·uv·版本
真实的菜11 小时前
Redis 从入门到精通(十二):典型业务场景实战 —— 排行榜、限流器、秒杀系统、Session 共享
数据库·redis·python
cup1112 小时前
[开源] Meta Assistant / 告别命令行,我为一堆 Python 脚本做了一个 Windows 任务栏的“家”
windows·python·工具·nuitka·脚本运行