Entity Framework 6 Async and .Wait () method

3

I have a system that is a Web Api, the control executes a class 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 async method, this is 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 on montarconfiguracao.Wait(); . I've done all test types, and I know that within Task it freezes at the .FirstOrDefaultAsync(); line.

First I thought it might be some error, then I put try catch , but it does not get error, then I thought it might be a problem in localhost , but on the server it hangs in the same place too.

I would like to use .Wait() because I can not put all methods as async at one time.

Adding more content:

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

    
asked by anonymous 12.06.2015 / 14:11

2 answers

3

You are experiencing a deadlock.

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

Assuming that the MontarConfiguracaoAsync method was implemented as follows:

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

    return result;
}

This method will execute something on another thread / IOCP, and when something completes, the control will return to the main thread to execute the return result statement. What happens is that the main thread has been locked in MontarConfiguracaoAsync().Wait() , and therefore the return result statement can not be executed - > deadlock.

For a more detailed explanation, read this excellent Stephen Cleary blog post: Do not Block on Async Code

To answer the @ramaral question:

  

The first code I know does not cause deadlock, does it use async in the method and does the second cause it?

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 any exceptions are thrown during the execution of the task, the exception will be captured and re-released (without changing the stack trace) in the thread that started the task.

Here is a possible sequence of events:

  • Main thread calls MontarConfiguracaoAsync
  • Main thread creates an instance of MYEntities and executes a query in the database, initiating an IOC (I / O Completion Port)
  • Main thread returns to IniciaProcesso method and creates a "continuation" with ContinueWith to be executed on the main thread
  • The query terminates, and the continuation is scheduled to run on the main thread as soon as it is free
  • The main thread continues to execute the remaining statements of IniciaProcesso and ends, releasing the main thread
  • The continuation is executed in the main thread
  • 12.06.2015 / 17:36
    2

    When doing montarconfiguracao.Wait(); it freezes because that's what Task.Wait() does: wait for the Task to finish.

    To prevent this from happening, 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 will have to do anything 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
             ...
             ...
        }
    } 
    
        
    12.06.2015 / 15:26