C#:在多个进程和/或线程之间共享数据的最佳方式

Posted

技术标签:

【中文标题】C#:在多个进程和/或线程之间共享数据的最佳方式【英文标题】:C#: best way to share data between multiple processes and/or threads 【发布时间】:2018-10-17 19:18:54 【问题描述】:

C# Restful Web 服务(在 Windows Server 2012 标准上)需要通过我在同一台服务器上运行的 C# 套接字服务器程序向设备发送命令。当网络服务试图向选定的设备发送命令时,相关设备的线程可以拾取该命令并将其发送给该设备。被选中后,应该被这个线程删除。同时,与设备n关联的线程n也可以拾取设备n的命令,线程n可以在拾取并发出该命令后删除该命令。请参考下面的系统架构图。

我的问题是什么是最好的方式(最有效、最可靠的解决方案)让 Web 服务发送命令数据并且这些套接字线程可以选择它们的关联命令,然后在发出这些命令后删除这些命令?这些命令可以保存到数据库中,socket线程可以定期检查数据库,但这不是有效的方法,尤其是在设备和用户量很大的情况下。命名管道是否适合这种情况,并且线程可以检查这些管道实例以找到关联的命令?

【问题讨论】:

Relevant @JohnWu 是的,相关,但不是很具体。我认为“Message Broker”的快速谷歌可能会显示您正在寻找的模式。我知道 Azure 服务总线可以做你想做的事,每个设备都有一个主题和该主题内的订阅。我确信其他主要的消息代理服务也可以做到这一点。 【参考方案1】:

Windows 服务可以有一个额外的套接字侦听器(或类似的)来接收任何连接设备的命令,并为每个设备维护一个BlockingCollection。拥有与每个设备的连接的线程可以简单地循环接收来自 BlockingColletoion 的消息并通过其套接字与设备交互。

【讨论】:

【参考方案2】:

我将在这里扩展我的评论 - 这是一种常见的情况,一些主要的软件公司(Azure、Amazon、Apache)已经实施了解决方案。它们都有多个发送者的概念,发送到单个消息代理,然后将每条消息直接转发给预期的接收者。为了让每个接收者接收消息,他们必须连接到消息代理,并声明他们是谁(或他们感兴趣的消息)。

需要注意的是,消息代理在服务器间通信中很常见,但在同一台机器上的进程间通信有更多选项(通常更简单、更有效)。因此,在选择解决方案之前,您需要考虑您的设备是否始终与单个套接字服务器进行通信,或者您是否会在某个时候横向扩展至多个实例。

使用第三方消息代理的一些优势:

它们可以为当前未连接的收件人缓冲消息 它们中的大多数都提供易于使用的 C# 包,因此需要的设置非常少 他们通常提供 99.99% 正常运行时间或更多的 SLA

与同一主机上的纯进程间解决方案相比存在一些缺点:

由于它们与外部消息代理服务器通信,它们具有更高的延迟 它们的最大吞吐量较低,这也是因为它们与外部服务器通信 它们通常要花钱(有时可以免费发送 100,000 条消息)

【讨论】:

【参考方案3】:

使用您的数据库

有很多方法可以执行此操作,例如- Memory mapped files 或 Anonymous pipes 或 MSMQ,我头顶的 3 个例子。但最简单的方法是使用您的数据库。具体来说,我会这样做:

    定义数据库表,这些表的结构使其可以保存设备列表或您希望用户能够更改或发送的命令。例如,您可能有一个列出每个用户的设备的表,或者一个包含要发送到设备的命令队列的表。

    对 Web 服务进行编程以更新数据库。例如,当用户想要“发送”命令时,只需将其添加到表中即可。不用担心硬件。

    编写 Windows 服务(或修改现有的服务)以偶尔读取 数据库并“同步”所有内容,例如向设备发送任何待处理的消息。同步后,将标志写回数据库,以便 Web 服务可以读取它并告诉用户命令已处理或更新完成。

这将为您提供一个非常简单、容错的解决方案,而无需在您的架构中引入任何新技术。

通过存储硬件快照,您还可以为各种有趣的可能性提供扩展点,例如“撤消”功能,或保存的快照,或可让您查看最终用户尝试设置的客户支持工具,或可让您了解用户如何使用您的产品的营销分析工具。

但最重要的功能是您可以崩溃/重新启动所有服务,并且解决方案会从中断的地方继续。所以它也很容易支持。希望您已经知道如何使用数据库。

【讨论】:

以上是关于C#:在多个进程和/或线程之间共享数据的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章

进程间通信方式——共享内存

C# 进程线程和多线程

进程之间的通信

c# 通过内存映射实现文件共享内存

在多个站点之间共享数据库数据的最佳方式是啥?

多线程,理论部分