private void RunAsync()
{
string param = "Hi";
Task.Run(() => MethodWithParameter(param));
}
private void MethodWithParameter(string param)
{
}
Editar
Devido à demanda popular, devo observar que o Taskiniciado será executado em paralelo com o thread de chamada. Assumindo o padrão TaskScheduler, usará o .NET ThreadPool. De qualquer forma, isso significa que você precisa levar em conta quaisquer parâmetros que estão sendo passados para o Taskcomo potencialmente sendo acessados por vários threads de uma vez, tornando-os um estado compartilhado. Isso inclui acessá-los no thread de chamada.
No meu código acima, esse caso é inteiramente discutível. Strings são imutáveis. É por isso que os usei como exemplo. Mas digamos que você não esteja usando um String...
Uma solução é usar asynce await. Isso, por padrão, irá capturar o SynchronizationContextdo thread de chamada e criar uma continuação para o resto do método após a chamada awaite anexá-lo ao criado Task. Se esse método estiver sendo executado no thread da GUI do WinForms, ele será do tipo WindowsFormsSynchronizationContext.
A continuação será executada após ser postada de volta no capturado SynchronizationContext- novamente apenas por padrão. Assim, você estará de volta ao tópico com o qual começou após a awaitligação. Você pode alterar isso de várias maneiras, principalmente usando ConfigureAwait. Em suma, o resto do que o método não continuará até que após a Taskcompletou em outro segmento. Mas o thread de chamada continuará a ser executado em paralelo, mas não o resto do método.
Essa espera para concluir a execução do resto do método pode ou não ser desejável. Se nada nesse método acessar posteriormente os parâmetros passados para o, Taskvocê pode não querer mais usar await.
Ou talvez você use esses parâmetros muito mais tarde no método. Não há razão para isso awaitimediatamente, pois você pode continuar fazendo o trabalho com segurança. Lembre-se de que você pode armazenar o Taskretornado em uma variável e awaitposteriormente - até mesmo no mesmo método. Por exemplo, uma vez que você precisa acessar os parâmetros passados com segurança depois de fazer um monte de outro trabalho. Novamente, você não precisa estar awaità Taskdireita ao executá-lo.
De qualquer forma, uma maneira simples de tornar esse thread-safe com relação aos parâmetros passados para Task.Runé fazer isso:
Você deve primeiro decorar RunAsynccom async:
private async void RunAsync()
Nota importante
De preferência, o método marcado não deve retornar void, como a documentação vinculada menciona. A exceção comum são os manipuladores de eventos, como cliques em botões e outros. Eles devem retornar vazios. Caso contrário, sempre tento retornar um ou ao usar . É uma boa prática por vários motivos.async TaskTask<TResult>async
Agora você pode awaitexecutar o exemplo Taskabaixo. Você não pode usar awaitsem async.
await Task.Run(() => MethodWithParameter(param));
Portanto, em geral, se você fizer awaita tarefa, poderá evitar tratar os parâmetros passados como um recurso potencialmente compartilhado com todas as armadilhas de modificar algo de vários threads de uma vez. Além disso, tome cuidado com os fechamentos . Não vou cobri-los em profundidade, mas o artigo vinculado faz um ótimo trabalho.
Nota
Um pouco fora do assunto, mas tome cuidado ao usar qualquer tipo de "bloqueio" no thread da GUI do WinForms devido a ele estar marcado com [STAThread]. O uso awaitnão bloqueia de forma alguma, mas às vezes vejo que é usado em conjunto com algum tipo de bloqueio.
"Block" está entre aspas porque você tecnicamente não pode bloquear o thread da GUI do WinForms . Sim, se você usar locko thread da GUI do WinForms, ele ainda enviará mensagens, apesar de você pensar que está "bloqueado". Não é.
Isso pode causar problemas bizarros em casos muito raros. Uma das razões pelas quais você nunca quer usar um lockao pintar, por exemplo. Mas esse é um caso marginal e complexo; no entanto, eu já vi isso causar problemas malucos. Então, eu anotei isso por uma questão de integridade.