First, I see that you are confusing asynchronism with parallelism, although the two are closely related, one is quite different from the other.
When scheduling asynchronously, the task should provide a return mechanism, usually a delegate as in the example below.
private delegate void NotificacaoIosTodos(string titulo, int posicao, int unidadeId);
public void MinhaAction()
{
var argumentos = new object[] { titulo, configuracaoItem.Posicao, unidade.UnidadeAtual };
var notificacao = new NotificacaoIosTodos(_notificacaoController.NotificacaoIosTodos, argumentos);
notificacao.BeginInvoke(new AsyncCallback(NotificacoesCallback), notificacao);
}
public void NotificacoesCallback()
{
DoSomething();
}
In the above example, the NotificacoesCallback
will be called as soon as the NotificacaoIosTodos
finishes, not allocating any additional resources between the call of MinhaAction
and NotificacoesCallback
.
Parallelism has the function of executing tasks simultaneously. One way to achieve this is to create a new Task
, remembering that you can wait for it to return.
public void MinhaAction()
{
var notificacao = Task.Run(() => _notificacaoController.NotificacaoIosTodos(titulo, configuracaoItem.Posicao, unidade.UnidadeAtual));
notificacao.Wait();
DoSomething();
}
In the example above, a new Task
is created. When calling Wait
you will be blocking Thread
current, so chances are you're allocating more resources than necessary.
The scenario is something that should be avoided, but the conditions below may bring some gain.
Example 1
public void MinhaAction()
{
var notificacao = Task.Run(() => _notificacaoController.NotificacaoIosTodos(titulo, configuracaoItem.Posicao, unidade.UnidadeAtual));
// DoSomething1 é executado ao mesmo tempo que NotificacaoIosTodos;
DoSomething1();
// Aqui a Thread atual é bloqueada até a conclusão de NotificacaoIosTodos
notificacao.Wait();
// Por fim é executado DoSomething2
DoSomething2();
}
Example 2
public void MinhaAction()
{
var notificacoes = new Task[10];
for (var posicao = 0; posicao < notificacoes.Length; posicao++)
notificacoes[posicao] = Task.Run(() => _notificacaoController.NotificacaoIosTodos(titulo, posicao, unidade.UnidadeAtual));
// As 10 notificações serão executadas em paralelo enquanto a Thread atual é bloqueada.
Task.WaitAll(notificacoes);
// Por fim é executado DoSomething2
DoSomething();
}
Now let's go back to asicronism in this case using the reserved words async/await
public async Task MinhaAction()
{
await _notificacaoController.NotificacaoIosTodos(titulo, configuracaoItem.Posicao, unidade.UnidadeAtual);
DoSomething();
}
internal async Task NotificacaoIosTodos(string titulo, int posicao, int unidadeId)
{
await ConsultaBancoDeDados();
}
In the example above, a new thread will not be created. Calling NotificacaoIosTodos
will synchronize within the current context. This behavior is quite useful when we need to do some I / O operation, such as reading a file or querying the database.
On the other hand, if we are going to do some CPU Bound operation, then it is interesting that this process runs on a separate Thread while the Thread > main is released, for this we use
Task.Run
.
public async Task MinhaAction()
{
await Task.Run(() => _notificacaoController.NotificacaoIosTodos(titulo, configuracaoItem.Posicao, unidade.UnidadeAtual));
DoSomething();
}
internal async Task NotificacaoIosTodos(string titulo, int posicao, int unidadeId)
{
await CalcularHashCemMilVezes();
}
Now a small example combining asynchronism with parallelism :
public async Task MinhaAction()
{
var notificacoes = new Task[10];
for (var posicao = 0; posicao < notificacoes.Length; posicao++)
notificacoes[posicao] = _notificacaoController.NotificacaoIosTodos(titulo, posicao, unidade.UnidadeAtual);
// As 10 notificações serão executadas em paralello enquanto a Thread atual é bloqueada.
await Task.WhenAll(notificacoes);
// Por fim é executado DoSomething2
DoSomething();
}
internal async Task NotificacaoIosTodos(string titulo, int posicao, int unidadeId)
{
await ConsultaBancoDeDados();
}
And as for async void
, avoid using it, unless the method is a fire and forget method, such as evento
or a method that its completion is not expected by another method (such as sending an email).
Finally, although Task.Run
does not make the execution asynchronous, it is possible to use the ContinueWith
method to add a return mechanism to Task
.
public async Task MinhaAction()
{
var notificacao = await Task.Run(() => _notificacaoController.NotificacaoIosTodos(titulo, configuracaoItem.Posicao, unidade.UnidadeAtual));
notificacao.ContinueWith(task => {
// task.Result possui o retorno de NotificacaoIosTodos
DoSomething(task.Result);
}, TaskContinuationOptions.OnlyOnRanToCompletion);
notificacao.ContinueWith(task => {
LogarErro(task.Exception.Message);
}, TaskContinuationOptions.OnlyOnFaulted);
}
internal async Task<bool> NotificacaoIosTodos(string titulo, int posicao, int unidadeId)
{
return await ConsultaBancoDeDados();
}