В чем разница между SynchronizationContext.Send и SynchronizationContext.Post - PullRequest
26 голосов
/ 18 марта 2010

Благодаря хорошей работе Джереми Миллера в Функциональное программирование для повседневной разработки .NET , у меня есть работающий исполнитель команд, который делает все, что я хочу (выполнять тяжелую работу с пулом потоков, отправлять результаты или ошибки вернуться к контексту синхронизации и даже опубликовать прогресс обратно в контекст синхронизации), но я не могу объяснить, почему он использует SynchronizationContext.Send из пула потоков и Synchronization.Post из Func перешел в метод, который делает тяжелую работу. Я прочитал документацию несколько раз, но я просто не могу понять, в чем разница. Что я должен получить из того факта, что один называется Send, а другой называется Post? Я чувствую, что магия заключается в том, что Send "запускает синхронный запрос" и Post "запускает асинхронный запрос", но оба запроса приходят из пула потоков и нуждаются в быть отправленным / опубликованным в ветке пользовательского интерфейса.

Может ли кто-нибудь объяснить разницу, даже если это просто мнемоническое устройство, которое позволяет мне узнать, когда выбирать одно из другого?

В случае, если это имеет значение, это мой тестовый код , где я использую Post для отправки прогресса обратно в пользовательский интерфейс:

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);
}

Этот метод _ExecuteCommand передается как параметр command ниже, в основном из исходной статьи, которая использует Send для отправки сообщения о завершении и ошибке обратно в пользовательский интерфейс:

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));
         }
     });
}

1 Ответ

29 голосов
/ 18 марта 2010

Отправить - синхронно: ждать ответа (или действие завершено)

Пост - асинхронный: сброс и продолжение

Итак, ваш пример использует правильные методы в нужные моменты. Нет необходимости останавливать цикл for до тех пор, пока не будет завершено обновление прогресса (наоборот).
И Execute хочет дождаться завершения действия, в противном случае обработка исключений не имеет смысла.

...