【问题标题】:From multithread to single thread从多线程到单线程
【发布时间】:2017-09-25 21:06:00
【问题描述】:

我正在运行一个事件驱动的 Windows 服务,每个事件都由它自己的线程处理。现在,这些事件通常以每秒 10 次左右的速度发生。事件的最后一个动作是将数据保存到数据库中。

如果保存数据失败,因为无法建立与数据库的连接,我希望遇到此问题的第一个线程以某个时间间隔(例如每 30 秒)启动一个新的重新连接任务。我希望简单地结束任何以下线程。任何时候都应该只运行一个重新连接的任务。

如何编写代码以使以下事件线程安全地知道已经有一个重新连接任务正在运行并结束它的生命?也许有一个很好的设计模式?

编辑: 遵循 FelixD 的建议链接:取消取消令牌会触发任务中的异常吗?

如果是这样,我可能会捕捉到异常,所以它会保存传入的 文件中的数据,而不是将其提交到数据库。我试图搜索这个,但我不清楚当任务被取消时会发生什么。

【问题讨论】:

  • @FelixD。如果我正确理解了这个想法,启动重新连接作业的第一个线程会取消其他正在运行的线程吗?据我了解取消令牌,线程将停止“工作中”。在我的场景中,我想在事件被取消之前保存数据(并在连接建立时提交)。我可以使用取消令牌来完成此操作吗?
  • 我想是的..this 也对你有帮助吗?
  • 为什么要让第一个线程尝试重新连接并处理所有其他线程?处理所有线程然后启动一个检查连接的新线程是否同样有效?
  • @Mr.Blonde 你不应该为所有线程保持一个连接。在 using 块内根据需要打开连接。 ADO.NET 使用连接池,因此您不必每次都打开一个新连接。通过尝试使用全局连接,您最终会损害性能和可伸缩性,因为锁会累积并导致过度阻塞和等待

标签: c# multithreading task


【解决方案1】:

我建议创建一个BlockingCollection,以及一个持续监控它的工作线程。当您的一个接收线程收到消息时,它会处理该消息,然后将其写入BlockingCollection,而不是尝试将其写入数据库。

监控BlockingCollection 的工作线程可以与数据库建立单个持久连接,并且可以写入单个记录,或者将它们批量进行批量更新,或者在数据库连接失败时将记录写入文件某种原因。

这种事情很容易设置直接使用BlockingCollection,或者你可以使用TPL Dataflow

【讨论】:

  • 如果我需要 FIFO,ConcurrentQueue 是否等同于 BlockingCollection?
  • @Mr.Blonde:BlockingCollection 的默认阻塞存储是ConcurrentQueueBlockingCollection 更容易使用。一个简单的例子见stackoverflow.com/questions/19847905/…
  • 谢谢。我相信您的设计建议可以完成我想要的。
【解决方案2】:

数据库连接丢失通常被描述为暂时性故障。经常发生这种情况是因为数据库无法为向其抛出的流量提供服务,因此它开始拒绝或超时连接。

您是否实际观察到此故障的发生,或者您是否预先发现了它?

您应该通过等待一段时间然后重试操作多次(包括打开新连接)来处理暂时性故障。对所有线程执行此操作。如果所有重试都失败,请准备回退到已知状态并返回错误。

我发现 Polly(由 .Net 基金会提供)对于以结构化方式处理这种行为非常有用。 http://www.thepollyproject.org/

【讨论】:

    猜你喜欢
    • 2018-06-03
    • 1970-01-01
    • 2016-07-22
    • 2015-10-19
    • 2012-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多