Calling an asynchronous and synchronous method

1

I have a synchronous method, in it I call another method of another controller that would have to be executed asynchronously.

I call this another method this way:

Task.Run(() => _notificacaoController.NotificacaoIosTodos(titulo,
configuracaoItem.Posicao,unidade.UnidadeAtual));

This is my method:

  internal void NotificacaoIosTodos(string titulo, int posicao, int unidadeId)
    {
        try
        {
            var unidade = _contexto.Unidade.FirstOrDefault(l => l.UnidadeId == unidadeId);
            var pessoas = _contexto.PessoaUnidade.Include(l => l.Pessoa)
                .Where(l => l.Pessoa.Dispositivo == (int)enumDispositivo.Ios && l.UnidadeId == unidadeId)
                .ToList();
            foreach (PessoaUnidade pessoa in pessoas)
            {
                Notificacao notificacao = new Notificacao {Posicao = posicao};
                _contexto.Notificacao.Add(notificacao);
                _contexto.SaveChanges();
                PessoaNotificacao pessoaNotificacao = new PessoaNotificacao
                {
                    Visualizado = false,
                    PessoaUnidade = pessoa,
                    Notificacao = notificacao
                };
                _contexto.PessoaNotificacao.Add(pessoaNotificacao);
                _contexto.SaveChanges();
            }

            Push.EnviarTodos(unidade.OneSignalAuth, unidade.OneSignalId, titulo, posicao, unidade.Nome);
        }
        catch (Exception)
        {
            throw;
        }
    }

I put the whole method, but my question is whether the method is working asynchronously or synchronously, should NotificacaoIosTodos be marked with async and using await ?

That way he is now already running on another thread asynchronously?

    
asked by anonymous 10.05.2017 / 16:43

2 answers

4

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();
}
    
10.05.2017 / 23:59
1
  

I put the whole method but my doubt and about the synchronicity   of this method, the NotificationAll method should be marked with   async and using yaait?

Whether it will be used as an asynchronous or synchronous choice is yours .

  

In this way he is now already running in another   thread asynchronously?

Yes, the method is running asynchronously. Also, it runs on a Thread.

But, on the contrary, an asynchronous call does not necessarily create a new Thread.

To use as async you will need to change it as in the example below:

internal void async NotificacaoIosTodos(string titulo, int posicao, int unidadeId)
{
  ...
}

And in the call use await , example:

await Task.Run(() => _notificacaoController.NotificacaoIosTodos(titulo,
configuracaoItem.Posicao, unidade.UnidadeAtual));

However, Task.Run already makes the job asynchronous.

    
10.05.2017 / 16:55