如何异步处理消息,在处理时丢弃任何新消息?

时间:2010-03-02 15:27:34

标签: c# multithreading event-handling messaging

我有一个C#应用程序订阅我们的邮件系统上的主题以进行价值更新。当一个新值进入时,我会进行一些处理,然后继续。问题是,更新可能比应用程序可以处理它们更快。我想要做的就是坚持最新的价值,所以我不想要一个队列。例如,源发布值“1”,我的应用程序接收它;在处理时,源在我的应用程序完成处理之前发布序列(2,3,4,5);我的应用程序然后处理值“5”,抛弃先前的值。

由于它基于专有的消息传递库,因此很难发布一个有效的代码示例,但我认为这是一个常见的模式,我只是无法弄清楚它的名称是什么......它似乎是处理函数必须在与消息传递回调不同的线程上运行,但我不确定如何组织它,例如如何通知该线程的值更改。关于我需要做什么的一般提示?

5 个答案:

答案 0 :(得分:2)

一种非常简单的方式可能是:

private IMessage _next;

public void ReceiveMessage(IMessage message)
{
    Interlocked.Exchange(ref _next, message);
}

public void Process()
{
    IMessage next = Interlocked.Exchange(ref _next, null);

    if (next != null)
    {
        //...
    }
}

答案 1 :(得分:1)

一般来说,人们使用邮件系统来防止丢失邮件。我对解决方案的初步反应是接收入站数据的线程,该入口数据试图将其传递给您的处理线程,如果处理线程已经在运行,那么您将丢弃数据并等待下一个元素并重复。

答案 2 :(得分:0)

这不是“模式”,但您可以使用共享数据结构来保存该值。如果从消息传递库中只收到一个值,那么一个简单的对象就可以。否则,您可以使用哈希表来存储多个消息值(如果需要)。

例如,在消息接收线程上:当消息进入时,使用其值添加/更新数据结构。在线程方面,您可以定期检查此数据结构以确保您仍具有相同的值。如果不这样做,则丢弃已经完成的任何处理,并使用新值重新处理。

当然,您需要确保数据结构在线程之间正确同步。

答案 3 :(得分:0)

显然,消息传递库的设计可以影响处理此问题的最佳方法。我过去是如何使用类似功能的库来完成它的,我有一个侦听事件的线程,并将它们放入队列,然后我让Threadpool工作人员将消息出列并处理它们。

您可以阅读多线程异步作业队列:

Mutlithreaded Job Queue

Work Queue Threading

答案 4 :(得分:0)

一种简单的方法是使用成员变量来保存最后接收的值,并用锁包装它。另一种方法是将传入值压入堆栈。当你准备好一个新值时,调用Stack.Pop()然后调用Stack.Clear():

public static class Incoming
{
    private static object locker = new object();
    private static object lastMessage = null;

    public static object GetMessage()
    {
        lock (locker)
        {
            object tempMessage = lastMessage;
            lastMessage = null;
            return tempMessage;
        }
    }
    public static void SetMessage(object messageArg)
    {
        lock (locker)
        {
            lastMessage = messageArg;
        }
    }

    private static Stack<object> messageStack = new Stack<object>();
    public static object GetMessageStack()
    {
        lock (locker)
        {
            object tempMessage = messageStack.Count > 0 ? messageStack.Pop() : null;
            messageStack.Clear();
            return tempMessage;
        }
    }
    public static void SetMessageStack(object messageArg)
    {
        lock (locker)
        {
            messageStack.Push(messageArg);
        }
    }
}

将处理函数放在单独的线程上是个好主意。使用处理线程中的回调方法来表示它已准备好接收另一条消息,或者让它发出信号表明已经完成,然后让主线程在收到消息时启动新的处理器线程(通过上面的SetMessage ...)