【问题标题】:LINQ's Select inside Task.Run skipping first value whereas ForEach does notLINQ\'s Select inside Task.Run 跳过第一个值,而 ForEach 没有
【发布时间】:2022-08-17 00:48:49
【问题描述】:

我有一个功能

public Task<IEnumerable<T>> GetVersionsAsync<T>(string key)
{
    var request = GetVersionsRequestBuilder.Create(_databaseName, _collectionName).WithKey(key);

    return Task.Run(() =>
    {
        var records = _myReader.GetAllVersionsForKey(request);        

        var returnValue = records.Select(record =>
        {
            var document = _mySerializer.Deserialize<T>(record.document);
            return document;
        });

        return returnValue;
    });
}

这是跳过第一个值并给出所有剩余结果

但是,如果我将 LINQ 部分更改为 ForEach,那么它会提供所有记录

var returnValue = new List<T>();

foreach (var record in records)
{
    var document = _mySerializer.Deserialize<T>(record.document);
    returnValue.Add(document);
}

return returnValue as IEnumerable<T>;

这是因为 LINQ 的 Select 投影在 Task.Run 内吗?

  • _myReader_mySerializer 是什么?这些线程安全性如何?
  • 这些是我的数据库读取器和序列化器,它们分别获取结果并对其进行反序列化。它们在 LINQ 和 ForEach sn-p 中是相同的。

标签: c# linq


【解决方案1】:

不是混合 IEnumerables 和 Tasks。 Deferred Execution 和并行执行在同一时间真的不能很好地结合在一起。

我不知道是什么具体来说触发你的怪异行为,但一般来说,你的任务是无用的,因为它没有做你认为它做的事情。它确实不是反序列化所有元素。该任务几乎立即完成,并返回您的 IEnumerable 状态机。只有当你实现它,你的任务完成后,它才会真正你打算用 LinQ 做什么。

所以,不要混合它。如果您希望它异步运行,请这样做,但要实现它:

公共任务<List> GetVersionsAsync(字符串键) { var request = GetVersionsRequestBuilder.Create(_databaseName, _collectionName).WithKey(key);

return Task.Run(() =>
{
    var records = _myReader.GetAllVersionsForKey(request);        

    var returnValue = records.Select(
        record => _mySerializer.Deserialize<T>(record.document)
    ).ToList(); // materialize it

    return returnValue;
});

}

【讨论】:

    猜你喜欢
    • 2021-04-08
    • 1970-01-01
    • 2019-02-16
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    相关资源
    最近更新 更多