首页 > 解决方案 > 在分布式系统中组织事件的执行并避免死锁

问题描述

我在系统中对事件进行优先级排序时遇到问题。我有一个简单的类,可以订阅彼此的输出

public interface INode<TIn, TOut> : IBaseNode
{
    event EventHandler<TOut> Output; 
    //Note: subscribe just calls node.Output += this.OnInput
    void Subscribe(IBaseNode node);
    void OnInput(object sender, TIn input)
} 

使用它,我可以通过订阅它们的输出将节点链接在一起

CarDealerNode.Subscribe(NewModelNode);
LoggerNode.Subscribe(CarDealerNode);

我的问题是,当一个事件触发时,它以一种半不确定的广度优先方式发生。我想保持这些事件的执行顺序,以便我可以以更动态的方式优先处理事件执行。

我的第一印象是使用一些优先级队列对任务进行排序,但这可能会导致问题,因为较低优先级的事情可能永远不会执行

public class SynchronizationInfo
{
    public SyncPriority Priority { get; set; } = SyncPriority.Normal;
    public object Sender { get; set; }
    public DateTime Created { get; set; } = DateTime.Now;
    public Task Operation { get; set; }
}

public class SynchronizationContext
{
    public PriorityQueue<SynchronizationInfo> ExecutionQueue = new PriorityQueue<SynchronizationInfo>();
    //...
}

但是,我仍然难以掌握确保不会发生死锁的方法,如果以比执行该优先级更快的速度添加高优先级的内容,则不会执行较低优先级的事件。

此外,仅仅因为某些事情的优先级过低并不意味着所有优先级较高的事情都应该优先,时间是一个重要因素。

是否有一种可靠有效的推荐方式来处理任务的优先执行。以一种没有任务经历死锁的方式,(例如,时间增加优先级以降低优先级以确保执行)?

标签: c#algorithmeventssynchronizationpriority-queue

解决方案


当我们可以有更多时,为什么还要有一个队列?

这适用于任何恒定的优先级计数,尽管优先级足够低。(据我所见,你有一个enum适合他们的,所以可能只有几个优先事项)。此外,我们不会使用优先级队列,而是使用几个普通队列。

  • 为每个优先级排队。该任务根据其优先级注册到队列中。对于每个任务,都会像@Funk 一样存储创建时间戳。
  • 当您希望处理下一个任务时,请检查每个队列中可用元素的时间戳。
  • 这使您可以检测长期过期的低优先级任务并提高其优先级。

可以通过多种方式增加优先级。例如:

  • 当队列中的时间足够长时,直接启动任务执行。(例如 high_creation_time > medium_creation_time + C -> 运行中优先级任务)
  • 将任务重新调度到优先级更高的队列中,而不是直接运行。

哪种方式更适合您,很难说。

这种方法的复杂性:

  • 添加新任务:O(1) - 只需将其添加到相应的队列中
  • 运行任务:O(1) - 假设我们有恒定数量的优先级,这只是检查所有队列并找到接下来应该运行的元素的问题。
  • 重新安排任务(如果适用) - 一推一弹出,因此 O(1)

推荐阅读