Entity Framework 6 Async and method . Wait()

Asked

Viewed 211 times

3

I have a system that is a Web Api, the control runs a classes like this:

public class CrawlBO
{
    public void IniciaProcesso()
    {
        ...


        CarregaConfiguracaoCrawlBO carregaconfiguracaocrawlbo = new CarregaConfiguracaoCrawlBO(type);
        Task<ConfiguracaoCrawlModel> montarconfiguracao = carregaconfiguracaocrawlbo.MontarConfiguracaoAsync(type);

        ...

        montarconfiguracao.Wait();
        conf = montarconfiguracao.Result;

        ...
    }

}

My class CarregaConfiguracaoCrawlBO has a method async, that’s the class:

public class CarregaConfiguracaoCrawlBO
{
    public async Task<ConfiguracaoCrawlModel> MontarConfiguracaoAsync(EnumOrigens type)
    {
        try
        {
            MYEntities db = new MYEntities ();
            int t = (int)type;

            CRAWL conf = await db.CRAWLs.Where(p => p.ID_ORIGEM == t).FirstOrDefaultAsync();

            ...

            return c;
        }
        catch (Exception ex)
        {

            throw ex;
        }
    }
}

The problem is that it freezes in the montarconfiguracao.Wait();. I did all kinds of tests, and I know inside the Task it freezes on the line of .FirstOrDefaultAsync();.

At first I thought it might be some mistake, so I put the try catch, but it does not take error, then I thought it could be problem in the localhost, but on the server it hangs in the same place too.

I’d like to use the .Wait() because I am not able to put all the methods as async at once.

Adding More Content:

I know he stops at .Wait() to wait for the task, but the problem that the task should take about 4 seconds, and it really freezes, an hour later and is still there in the task without doing anything

2 answers

3


You’re experiencing a deadlock.

Wait() and Result can lead to deadlocks depending on the Execution context.

Imagining that the method MontarConfiguracaoAsync was implemented as follows:

public Task<ConfiguracaoCrawlModel> MontarConfiguracaoAsync()
{
    var result = await something();

    return result;
}

This method will perform something another thread/IOCP and, when something complete, control will return to the main thread to execute the instruction return result. What happens is that the main thread is locked in the MontarConfiguracaoAsync().Wait(), and therefore the instruction return result cannot be executed -> deadlock.

For a more detailed explanation, read this excellent blog post by Stephen Cleary: Don’t Block on Async Code


To answer the @ramaral question:

the first code I know does not cause deadlock as it uses async in the method and the second causes or does not?

The solution using ContinueWith would not cause a deadlock. The only difference between using ContinueWith and await, as far as I know, is in Exception Handling. With await, if an exception is made during the execution of the task, the exception will be captured and re-launched (without changing the stack trace) in the thread that started the task.

Here’s a possible sequence of events:

  1. Main thread calls MontarConfiguracaoAsync
  2. Main thread creates an instance of MYEntities and execute a query in the database, starting an IOCP (I/O Completion Port)
  3. Main thread back to method IniciaProcesso and creates a "continuation" with ContinueWith which must be executed on the main thread
  4. The query ends, and the continuation is scheduled to run on the main thread once it is free
  5. The main thread continues to run the remaining instructions from IniciaProcesso and ends by releasing the main thread
  6. The following runs on the main thread

2

In doing montarconfiguracao.Wait(); he freezes because that’s what Task.Wait() makes: expect that the Task finalize.

So that this does not happen change the code to:

public class CrawlBO
{

        public async Task IniciaProcesso()
        {

                ...

                CarregaConfiguracaoCrawlBO carregaconfiguracaocrawlbo = new CarregaConfiguracaoCrawlBO(type);
                Task<ConfiguracaoCrawlModel> montarconfiguracao = carregaconfiguracaocrawlbo.MontarConfiguracaoAsync(type);

                ...

                conf = await montarconfiguracao;
                //Após a linha anterior o método retorna

                //O código a partir daqui é executado após a Task finalizar
                // pode usar o valor de conf
                ...
        }

}  

If you do not want/can use async in the method you have to do something like this:

public class CrawlBO
{

    public void IniciaProcesso()
    {

        ...

        CarregaConfiguracaoCrawlBO carregaconfiguracaocrawlbo = new CarregaConfiguracaoCrawlBO(type);
        Task<ConfiguracaoCrawlModel> montarconfiguracao = carregaconfiguracaocrawlbo.MontarConfiguracaoAsync(type);

        ...

        montarconfiguracao.ContinueWith(t =>
            {
                //O código aqui é executado após a Task finalizar
                conf = t.Result;
            }, TaskScheduler.FromCurrentSynchronizationContext());

         //O código aqui é executado antes da task finalizar
         ...
         ...
    }
} 
  • I think I didn’t write well, the problem is that it freezes even! If you run the .FirstOrDefault without the async it runs in 3 seconds, but with the async he freezes for more than an hour and I’ve never seen him leave the Wait(). I’ve improved the question.

  • You in the method MontarConfiguracaoAsync() is returning to variable c was error when posting the code or is it even so? The method should return conf.

  • @user3517631 This is a deadlock, see my answer for more details.

  • @dcastro Ask me a question: the first code I know does not cause deadlock, for use async in the method and whether or not the latter causes?

  • @ramaral Good question - I edited my answer to answer that question too (did not fit in a comment)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.