private void RunAsync()
{
string param = "Hi";
Task.Run(() => MethodWithParameter(param));
}
private void MethodWithParameter(string param)
{
}
редактировать
По многочисленным просьбам я должен отметить, что Task
запущенный будет работать параллельно с вызывающим потоком. Предполагая, что по умолчанию TaskScheduler
будет использоваться .NET ThreadPool
. В любом случае, это означает, что вам необходимо учитывать любой передаваемый параметр (ы) Task
как потенциально доступный для нескольких потоков одновременно, делая их общим состоянием. Это включает доступ к ним в вызывающем потоке.
В моем приведенном выше коде этот случай совершенно спорный. Строки неизменны. Вот почему я использовал их в качестве примера. Но скажите, что вы не используете String
...
Одно из решений - использовать async
и await
. Это, по умолчанию, захватывает SynchronizationContext
вызывающий поток и создает продолжение для остальной части метода после вызова await
и присоединяет его к созданному Task
. Если этот метод выполняется в потоке графического интерфейса WinForms, он будет типа WindowsFormsSynchronizationContext
.
Продолжение будет запущено после отправки обратно в захваченное SynchronizationContext
- опять же только по умолчанию. Так что после await
звонка вы вернетесь к теме, с которой начали . Вы можете изменить это разными способами, в частности, используя ConfigureAwait
. Короче говоря, остальная часть этого метода не будет продолжаться до тех пор , послеTask
завершения другого потока. Но вызывающий поток будет продолжать работать параллельно, а не остальная часть метода.
Это ожидание завершения выполнения остальной части метода может быть или нежелательно. Если в дальнейшем ничто в этом методе не обращается к параметрам, переданным в, возможно, Task
вы вообще не захотите использовать await
.
Или, может быть, вы используете эти параметры намного позже в методе. Нет причин await
сразу же, так как вы можете спокойно продолжать работу. Помните, что вы можете сохранить Task
возвращаемое значение в переменной, а await
позже - даже в том же методе. Например, когда вам нужно безопасно получить доступ к переданным параметрам после выполнения кучи другой работы. Опять же, вам не нужно делать await
это Task
справа при запуске.
В любом случае, простой способ сделать это потокобезопасным по отношению к переданным параметрам Task.Run
- это сделать следующее:
Вы должны сначала украсить RunAsync
с async
:
private async void RunAsync()
Важная заметка
Желательно, чтобы отмеченный метод не возвращал void, как упоминается в связанной документации. Распространенным исключением из этого правила являются обработчики событий, такие как нажатие кнопки и т.п. Они должны вернуться в пустоту. В противном случае я всегда стараюсь вернуть или при использовании . Это хорошая практика по нескольким причинам.async
Task
Task<TResult>
async
Теперь вы можете await
запустить Task
как показано ниже. Вы не можете использовать await
без него async
.
await Task.Run(() => MethodWithParameter(param));
Итак, в целом, если вы await
выполняете задачу, вы можете избежать обработки переданных параметров как потенциально разделяемого ресурса со всеми подводными камнями изменения чего-либо сразу из нескольких потоков. Также остерегайтесь закрытия . Я не буду описывать их подробно, но связанная статья отлично справляется с этим.
Примечание
Немного не по теме, но будьте осторожны при использовании любого типа «блокировки» потока графического интерфейса WinForms из-за того, что он помечен значком [STAThread]
. Использование await
не будет блокировать вообще, но иногда я вижу, что оно используется в сочетании с какой-то блокировкой.
«Блокировать» заключено в кавычки, потому что вы технически не можете заблокировать поток графического интерфейса WinForms . Да, если вы используете lock
поток графического интерфейса WinForms, он все равно будет перекачивать сообщения, несмотря на то, что вы думаете, что он «заблокирован». Это не.
В очень редких случаях это может вызвать странные проблемы. Одна из причин, по которой вы никогда не захотите использовать lock
, например, при рисовании. Но это крайний и сложный случай; однако я видел, как это вызывает сумасшедшие проблемы. Поэтому я отметил это для полноты картины.