SynchronizationContext.Send和SynchronizationContext.Post有什么区别?

36

感谢Jeremy Miller在Functional Programming For Everyday .NET Development中的好工作,我有一个可行的命令执行器,它可以做我想做的一切(在线程池中进行繁重的工作,将结果或错误发送回同步上下文,甚至将进度发布回同步上下文),但我无法解释为什么它从线程池使用SynchronizationContext.Send并且从执行繁重工作的方法传递的Func中使用Synchronization.Post。我已经多次阅读了文档,但我只是无法深刻理解它们之间的区别。我应该从一个被称为Send和另一个被称为Post的事实中获得什么?我意识到奇妙之处在于Send“开始一个同步请求”,而Post“开始一个异步请求”,但两个请求都来自线程池,并且需要发送/发布回UI线程

有人可以解释一下它们之间的区别吗?即使只是一个提示设备,让我知道何时选择其中之一?

如果有关系的话,这是我使用Post将进度发送回UI的测试代码

private Action _ExecuteCommand
                (SynchronizationContext context
                 , Action<int, int> progress
                 , Action<int, int> after)
{
    int count = 3;
    int accumulatedValue = 0;
    int threadId = Thread.CurrentThread.ManagedThreadId;
    for (int i = 0; i < count; i++)
    {
        Thread.Sleep(1000);
        context.Post(delegate { progress(i + 1, threadId); });
        accumulatedValue += i;
    }

    return () => after(threadId, accumulatedValue);
}

下面的command参数通常是从原来的文章中传入的_ExecuteCommand方法,使用Send发送完成和错误消息回到UI:

public void Execute(Func<Action> command, Action<Exception> error)
{
    ThreadPool.QueueUserWorkItem(o =>
     {
         try
         {
             Action continuation = command();
             _Context.Send(s => continuation());
         }
         catch (Exception e)
         {
             _Context.Send(s => error(e));
         }
     });
}

7
它们的方法名取得真的很糟糕。 - Igby Largeman
1个回答

37

发送 - 同步: 等待答复(或操作完成)

发布 - 异步: 投递并继续

因此,您的示例在正确时使用了正确的方法。没有必要暂停for循环直到进度更新完成(相反)。
并且Execute确实希望等待Action完成,否则异常处理就没有意义。


如果我使用Post而不是Send,就不会出现错误。这只涉及到我是否需要线程池任务暂停以便消息被发送/发布。对吗? - flipdoubt
2
我仍然对此感到困惑。我以为同步上下文会为您提供一种在UI线程上执行某些工作的简便方法,这样您就不必等待它了吗?还是它的工作方式是这样的:您正在后台线程上执行一些工作,在中间需要进行一些UI工作,然后继续在后台线程上执行。如果使用Send,则后台线程在UI工作完成之前不会继续执行第二部分,但是如果使用Post,则后台线程将继续工作,而无需等待UI线程工作完成? - The Muffin Man
3
易于记忆:你不需要等待“邮寄”,只需希望它能传递你的信息。 - VMAtm
1
@TheMuffinMan 命名可能看起来有些愚蠢或令人困惑,但这是因为它基于较低级别的抽象。大多数使用SynchronizationContext的人只关心同步或异步调用方法——就像你所说的那样;然而,在稍微低一级的层面上,这是通过消息和消息处理来处理的。在那个层面上,命名大多是有意义的,尽管Send和SendAsync可能更好。话虽如此,考虑到它的使用方式和时间,Invoke和InvokeAsync可能更直接明了。 - Daniel
Post, Send - Legends

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接