首页 > 解决方案 > 为什么在一种情况下 GetAwaiter() 会阻止我的应用程序而在另一个应用程序中没有被阻止?

问题描述

我有 2 个项目,都使用 Net 5、实体框架 Net 5 和异步。唯一的区别是被阻止的项目使用Sql Server,而另一个使用Sqlite。但我猜数据库不是这个原因。

项目 1,即被阻止:

public void Main()
{
    SqlServerEFNet5 miRepository = new SqlServerEFNet5();
    miRepository.GetAllMyRowsAsync().GetAwaiter().GetResult();
}


public Task<List<MyType> GetAllMyRowsAsync()
{
    using (ContextEfNet5 dbContext = new ContextEfNet5(_optionsDbContext))
    {
        return await dbContext.MyEntities.FromSqlRaw("Select * from MyType").ToListAsync().ConfigureAwait(false);
    }
}

我的项目2,它没有被阻止:

private void Main()
{
    MyViewModelProperty.AddRange(Service.Service.GetAllMyRowsAsync().GetAwaiter().GetResult()));
}


public static async Task<List<MyType>> GetAllMyRowsAsync()
{
    using (Context myDbContext = new Context())
    {
        return await myDbContext.MyType.ToListAsync().ConfigureAwait(false);
    }
}

真的在我的第二个项目中我不使用原始 sql 查询,但我尝试在我的第一个项目中只使用纯 linq 并且仍然被阻止。

另外,在我的第一个项目中,我没有填充视图模型的集合,它可能会受到影响,因为它被视图使用,但在我的第二个项目中,我填充了视图模型的集合,所以它不是问题。

我不明白为什么在一种情况下它被阻止而在另一种情况下没有。

编辑01:

如果我在项目1中使用此代码,则不会被阻止:

        Task<int> miTask = Task<int>.Run(() => { return 0; });

        int myIntResult = miTask.GetAwaiter().GetResult();

编辑02:另一个问题的建议解决方案对我没有帮助,因为它建议使用await,但我不能使用它,因为我必须在构造函数中调用这个异步代码,而构造函数不能是异步的。

编辑 03:我在这个How would I run an async Task<T> 方法中找到了同步?它工作的帮手。

标签: c#async-await

解决方案


好的,想通了。僵局是因为SynchronizationContext它在对您的问题的评论中多次说明它正在捕获。通常解决方案是一直使用await,或者ConfigureAwait(false),你正在做的。但!

如此处所述(阻止黑客部分): https ://docs.microsoft.com/en-us/archive/msdn-magazine/2015/july/async-programming-brownfield-async-development

如果 Microsoft/EF 在某处使用从旧的基于事件的异步模式进行转换,那么ConfigureAwait(false)将不起作用,因为无论如何都已经捕获了上下文。

结果他们做了这样的转换,这里是SqlCommandSqlServer 的来源:

https://github.com/dotnet/SqlClient/blob/bd89b6433892214eed41e97afb0a9430d11d4681/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs

在那里寻找第2996行。

现在为什么 SqlLite 工作正常 - 因为 SqlLite 不支持异步 I/O,所以 SqlLite 的所有异步都是假的,你可以在源代码中清楚地看到它SqliteCommand

https://github.com/dotnet/efcore/blob/main/src/Microsoft.Data.Sqlite.Core/SqliteCommand.cs

406行。

“假”的解释在这里 - https://docs.microsoft.com/en-us/dotnet/standard/data/sqlite/async


推荐阅读