c# - 对象引用在多层异步等待操作中丢失

标签 c# .net asynchronous garbage-collection async-await

我遇到了一些行为,这些行为让我对垃圾收集器的异步等待模式的行为感到有些困惑。这是对生产代码的解释。

public async Task CreateProduct(int id)
{
    Product result = factory.Create(id);
    await AssignPrices(result);
    GC.KeepAlive(result);
    Assert.That(result.Prices.Count == 1); //this is true   
}

public async Task AssignPrices(Product value)
{
    foreach (var engine in pricingEngines)
    {
        await engine.AddPrice(value);
    }
}

public class DefaultPricingEngine
{
    public async Task AddPrice(Product value)
    {
        var price = await _externalApi.GetPrice();
        value.Prices.Add(price);
    }
}

class Product
{
  public int Id{get;set;}
  public string Name {get;set;}
  public List<decimal> Prices {get;set;}
}

如果我省略 GC.KeepAlive,它似乎会恢复到最初创建的产品。好像我保留它一样,价格按预期添加。

这里到底发生了什么导致清理.. GC.KeepAlive 是否真的发生了误报。

最佳答案

这与引用或垃圾收集无关。

您调用 AssignPrices,这是一个异步方法,无需等待它。这意味着您手上有竞争条件。

async 方法将在调用线程上同步运行,直到到达第一个 await 并且该方法返回控制权以及代表操作其余部分的任务。如果您不等待它(或同步阻止它),调用方法将与未等待的异步操作并行运行。

使用 GC.KeepAlive 只能通过延迟调用方法来实现,而 AssignPrices 有机会完成。

您应该等待操作,只有在操作完成后才能继续。您还应该向异步方法添加“Async”后缀,这有助于提醒您等待它。

public async Task CreateProductAsync(int id)
{
    Product result = factory.Create(id);
    await AssignPricesAsync(result);
    Assert.That(result.Prices.Count == 1);
}

关于c# - 对象引用在多层异步等待操作中丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33306490/

相关文章:

c# - 使用 C# 和 Sheets API v4 更新单元格

c# - Windows 窗体控件是否可以具有仅设计时属性?

c# - 为什么我的 C++ 互操作可以在 .Net 4.5 上运行,但不能在 4 上运行

c# - DllNotFoundException,但 DLL 存在

c# - 使用 JSON.net 序列化时忽略接口(interface)中定义的属性

c# - LINQ扩展方法求助二

.net - 在 Windows 窗体应用程序中使用 C++/CLI 的命名空间混淆

javascript - loadasync 函数导入的外部脚本什么时候执行?

.net - 如何使用响应式框架将两个异步操作链接在一起?

java - 内部类扩展 Asynctask,外部类扩展 Activity,然后从另一个 Activity 扩展外部类。这是一个不好的做法吗?