gpt4 book ai didi

c# - 通过使用带有 async/await 的 Linq 延迟执行而感到震惊

转载 作者:行者123 更新时间:2023-12-02 16:00:24 25 4
gpt4 key购买 nike

我是 async/await 的新手,正在修改它以使用任务列表对对象列表执行操作。我使用 Linq 生成对象列表和任务列表。下面的示例看起来有点做作,但它是我的实际代码的简化版本。

我发现,当如图所示执行代码时,在所有任务完成后(在等待之后),对象的 Now 属性都没有更新,并且所有任务的状态仍然为“正在运行”。

我发现,通过 .ToList<>() 将对象和任务转换为实际列表来消除 Linq 延迟执行,我的代码按预期工作(对象已填充,任务全部运行至完成)。

我熟悉 Linq 延迟执行,但我真的很困惑这段代码中发生了什么(没有发生什么)。我可能在 async/await 方面犯了一个菜鸟错误...这是什么?

private class Foo {
public DateTime Now { get; set; }
}

private void Button_Click( object sender, EventArgs e ) {
PopulateDates();
}

private async void PopulateDates() {
var ordinals = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, };

var foos = ordinals.Select( o => new Foo() ); //.ToList();

var tasks = foos.Select( f => PopulateDateAsync( f ) ); //.ToList();

await Task.WhenAll( tasks );

var firstNow = foos.ElementAt( 0 ).Now;
var firstTaskStatus = tasks.ElementAt( 0 ).Status;
}

private Task PopulateDateAsync( Foo foo ) {
return Task.Run( () => PopulateDate( foo ) );
}

private void PopulateDate( Foo foo ) {
Thread.Sleep( 2000 );
foo.Now = DateTime.Now;
}

最佳答案

您的问题是由于 LINQ 的延迟执行造成的。特别是,Task.WhenAll 正在适本地等待任务完成。但是,当您调用 ElementAt 时,会重新评估序列,创建新的 FooTask

所以,这也行不通:

var ordinals = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, };

var foos = ordinals.Select( o => new Foo() ); //.ToList();

// Get the first Foo, creating it.
var first = foos.ElementAt(0);

// This gets a *different* Foo. It creates it again.
var other = foos.ElementAt(0);

MessageBox.Show((first == other).ToString()); // Displays "false"

一般来说,在处理任何具有副作用的操作(包括启动 async 操作)时,最好“具体化”序列(使用 ToArray 或类似方法)。 Task.WhenAll 将在内部具体化您的序列,但如果您再次评估它(例如 ElementAt),您会得到意外的行为。

关于c# - 通过使用带有 async/await 的 Linq 延迟执行而感到震惊,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17381727/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com