Eu realmente gosto desta pergunta:
Maneira mais simples de fazer um método de fogo e esquecer em C #?
Eu só quero saber que agora que temos extensões paralelas em C # 4.0, há uma maneira melhor e mais limpa de fazer Fire & Forget com Parallel linq?
c#
.net
.net-4.0
task-parallel-library
fire-and-forget
Jonathon Kresner
fonte
fonte
Respostas:
Não é uma resposta para 4.0, mas vale a pena notar que no .Net 4.5 você pode tornar isso ainda mais simples com:
O pragma é desativar o aviso que informa que você está executando esta tarefa como disparar e esquecer.
Se o método dentro das chaves retornar uma Tarefa:
Vamos decompô-lo:
Task.Run retorna uma Tarefa, que gera um aviso do compilador (aviso CS4014) observando que esse código será executado em segundo plano - é exatamente o que você queria, portanto, desabilitamos o aviso 4014.
Por padrão, as Tarefas tentam "Marshal de volta para o Thread original", o que significa que esta Tarefa será executada em segundo plano e, em seguida, tentará retornar ao Thread que a iniciou. Freqüentemente, dispare e esqueça as Tarefas terminam depois que o Thread original é concluído. Isso fará com que uma ThreadAbortException seja lançada. Na maioria dos casos, isso é inofensivo - é apenas dizer a você, eu tentei voltar, falhei, mas você não se importa de qualquer maneira. Mas ainda é um pouco barulhento ter ThreadAbortExceptions em seus logs em produção ou em seu depurador no dev local.
.ConfigureAwait(false)
é apenas uma maneira de ficar organizado e dizer explicitamente, execute isso em segundo plano e é isso.Como isso é prolixo, especialmente o pragma feio, uso um método de biblioteca para isso:
Uso:
fonte
ConfigureAwait(false)
emTask.Run
quando você não fazawait
a tarefa. O objetivo da função está em seu nome: "configure await ". Se você não fizerawait
a tarefa, não registrará uma continuação e não haverá nenhum código para a tarefa "empacotar de volta ao thread original", como você diz. O maior risco é de uma exceção não observada ser relançada no encadeamento do finalizador, que esta resposta nem mesmo aborda.#Disable Warning BC42358
Com a
Task
classe sim, mas PLINQ é realmente para consultar coleções.Algo como o seguinte fará isso com a Tarefa.
Ou mesmo ...
Ou...
Onde
FireAway
estáEntão, em virtude da concisão do nome da classe e do método, isso supera a versão do threadpool por entre seis e dezenove caracteres, dependendo do que você escolher :)
fonte
fire and forget in ASP.NET WebForms and windows.close()
:?Eu tenho alguns problemas com a resposta principal a esta pergunta.
Em primeiro lugar, em uma situação verdadeira de fogo e esquecimento , você provavelmente não
await
executará a tarefa, por isso é inútil anexarConfigureAwait(false)
. Se você nãoawait
definir o valor retornado porConfigureAwait
, ele não terá nenhum efeito.Em segundo lugar, você precisa estar ciente do que acontece quando a tarefa é concluída com uma exceção. Considere a solução simples que @ ade-miller sugeriu:
Isso introduz um perigo: se uma exceção não tratada escapa
SomeMethod()
, nunca será observado que exceção, e podem 1 seja relançada no segmento finalizador, batendo sua aplicação. Portanto, eu recomendaria usar um método auxiliar para garantir que quaisquer exceções resultantes sejam observadas.Você poderia escrever algo assim:
Essa implementação deve ter sobrecarga mínima: a continuação só é chamada se a tarefa não for concluída com êxito e deve ser chamada de forma síncrona (em vez de ser agendada separadamente da tarefa original). No caso "preguiçoso", você nem mesmo incorrerá em uma alocação para o delegado de continuação.
Iniciar uma operação assíncrona torna-se trivial:
1. Esse era o comportamento padrão no .NET 4.0. No .NET 4.5, o comportamento padrão foi alterado de forma que exceções não observadas não fossem relançadas no encadeamento do finalizador (embora você ainda possa observá-las por meio do evento UnobservedTaskException em TaskScheduler). No entanto, a configuração padrão pode ser substituída e, mesmo se seu aplicativo exigir .NET 4.5, você não deve presumir que as exceções de tarefas não observadas serão inofensivas.
fonte
ContinueWith
for invocado devido ao cancelamento, a propriedade de exceção do antecedente será Null e uma exceção de referência nula será lançada. Definir a opção de continuação de tarefa comoOnlyOnFaulted
eliminará a necessidade de verificação de nulo ou verificará se a exceção é nula antes de usá-la.Task
torna-se um detalhe de implementação.Task
" não é o mesmo que "Quero uma maneira simples de iniciar uma operação em segundo plano, nunca observe seu resultado e não me importo com o mecanismo usado para fazer isso. " Com base nisso, mantenho minha resposta à pergunta que foi feita .fire and forget
em ASP.NET WebForms ewindows.close()
?Apenas para corrigir algum problema que vai acontecer com a resposta de Mike Strobel:
Se você usar
var task = Task.Run(action)
e depois de atribuir uma continuação a essa tarefa, correrá o risco deTask
lançar alguma exceção antes de atribuir uma continuação do manipulador de exceção aoTask
. Portanto, a classe abaixo deve estar livre deste risco:Aqui, o
task
não é executado diretamente, em vez disso, é criado, uma continuação é atribuída, e somente então a tarefa é executada para eliminar o risco de a tarefa completar a execução (ou lançar alguma exceção) antes de atribuir uma continuação.O
Run
método aqui retorna a continuação,Task
então posso escrever testes de unidade, certificando-se de que a execução seja concluída. Você pode ignorá-lo com segurança em seu uso.fonte