Control.Invoke vs Tasks с помощью TaskScheduler - PullRequest
5 голосов
/ 28 апреля 2011

Я просмотрел все и не могу найти ответ.Лучше, хуже или безразлично использовать:

{
...
RefreshPaintDelegate PaintDelegate = new RefreshPaintDelegate(RefreshPaint);
Control.Invoke(PaintDelegate);
}

protected void RefreshPaint()
{
    this.Refresh();
}

... или ...

Task.Factory.StartNew(() =>
{
    this.Refresh();
},
CancellationToken.None,
TaskCreationOptions.None,
uiScheduler);

Ответы [ 2 ]

3 голосов
/ 28 апреля 2011

Предполагая, что uiScheduler является планировщиком, который будет делегировать вызовы потоку пользовательского интерфейса, я бы сказал, что функционально использование этих двух безразлично (за исключением того, что вызов Control.Invoke будет блокироваться до завершения вызова, тогда как вызов Task не будет, однако, вы всегда можете использовать Control.BeginInvoke, чтобы сделать их семантически эквивалентными).

С семантической точки зрения я бы сказал, что использование Control.Invoke(PaintDelegate) - гораздо лучший подход; при использовании Task вы делаете неявное объявление о том, что хотите выполнить единицу работы, и обычно эта единица работы имеет контекст планирования вместе с другими единицами работы, именно планировщик определяет, как эта работа делегируется (как правило, он многопоточный, но в этом случае он маршалируется в поток пользовательского интерфейса). Следует также сказать, что нет четкой связи между uiScheduler и Control, которая связана с потоком пользовательского интерфейса, что вызов должен быть выполнен один (как правило, они все одинаковы, но возможно иметь несколько UI темы, хотя и очень редко).

Тем не менее, при использовании Control.Invoke цель того, что вы хотите сделать, ясна: вы хотите перенаправить вызов в поток пользовательского интерфейса, на который Control отправляет сообщения, и этот вызов прекрасно это показывает.

Я думаю, что лучший вариант - использовать экземпляр SynchronizationContext; он абстрагирует тот факт, что вам нужно синхронизировать вызовы с этим контекстом, в отличие от двух других вариантов, которые либо неоднозначны относительно цели в вызове (Task), либо очень специфичны в том, как это делается (Control.Invoke). * * тысячу двадцать-один

0 голосов
/ 28 апреля 2011

Это не одно и то же. Первая версия будет блокировать вызывающий поток, пока поток пользовательского интерфейса не будет готов вызвать метод. Для неблокирующей версии вы должны использовать Control.BeginInvoke, которая также немедленно возвращается.

Кроме этого (если вы сравниваете Task с потоком Thread Pool), разница в их использовании невелика.

[Изменить]

В этом случае нет никакой разницы между Task.Factory.StartNew и Control.BeginInvoke (но не Invoke, как я писал выше), поскольку существует только один поток GUI, который может выполнить ваш код. Независимо от того, сколько вызовов вы делаете, используя один из них, они все равно будут выполняться последовательно, когда поток пользовательского интерфейса станет свободным.

...