可以保证变量的值会传递到一个新的运行任务吗?

huangapple go评论60阅读模式
英文:

Can I be guaranteed that a variable value will be passed along to a new running Task?

问题

我是否可以假定以下代码将始终通过我的断言?我担心索引值。我不确定作用域值是否会传递到 Task.Run 的 lambda 表达式中。我认为它会像 attributesChunked 值一样作用域化。但我想要一些确认。

var tasks = new List<Task>();
var attributes = new string[4]{ "att1", "att2", "att3", "att4" };
var chunkIndex = -1;
foreach (var attributesChunked in attributes.Chunk(2))
{
    var index = Interlocked.Increment(ref chunkIndex);
    tasks.Add(Task.Run(() =>
    {
        if (index == 0)
             Assert.Equal("attr1", attributesChunked.First());
        if (index == 2)
             Assert.Equal("attr3", attributesChunked.First());
    }));
}
await Task.WhenAll(tasks);
英文:

Can I assume the following code will always pass my assertions? I'm a worried about the index value. I'm not sure if the scoped value will be passed along to the Task.Run lambda expression. I think it will be scoped just like the attributesChunked value seems to be. But I'd like some confirmation.

var tasks = new List&lt;Task&gt;();
var attributes = new string[4]{ &quot;att1&quot;, &quot;att2&quot;, &quot;att3&quot;, &quot;att4&quot; };
var chunkIndex = -1;
foreach (var attributesChunked in attributes.Chunk(2))
{
    var index = Interlocked.Increment(ref chunkIndex);
    tasks.Add(Task.Run(() =&gt;
    {
        if (index == 0)
             Assert.Equal(&quot;attr1&quot;, attributesChunked.First());
        if (index == 2)
             Assert.Equal(&quot;attr3&quot;, attributesChunked.First());
    }
}
await Task.WhenAll(tasks);

答案1

得分: 2

对于您创建的每个任务,您都引入了一个在该迭代中声明的索引变量的闭包。因此,是的,您的任务将使用正确的值,可以使用以下代码进行测试:

static async Task Main(string[] args)
{
    var tasks = new List<Task>();
    var attributes = new string[4] { "att1", "att2", "att3", "att4" };
    var chunkIndex = -1;
    foreach (var attributesChunked in attributes.Chunk(2))
    {
        var index = Interlocked.Increment(ref chunkIndex);
        tasks.Add(Task.Run(async () =>
        {
            // 模拟一些工作...
            await Task.Delay(50);
            Console.WriteLine($"index: {index}");
        }));
    }
    await Task.WhenAll(tasks);
}

结果:

index: 0
index: 1

请注意,输出的顺序完全取决于各个任务的调度,无法预测...

有用的参考链接:https://stackoverflow.com/questions/428617/what-are-closures-in-net

英文:

For each task you create, you are introducing a closure on the index variable declared in that iteration. So yes your Task will use the right value, as can be tested using following code:

static async Task Main(string[] args)
{
    var tasks = new List&lt;Task&gt;();
    var attributes = new string[4] { &quot;att1&quot;, &quot;att2&quot;, &quot;att3&quot;, &quot;att4&quot; };
    var chunkIndex = -1;
    foreach (var attributesChunked in attributes.Chunk(2))
    {
        var index = Interlocked.Increment(ref chunkIndex);
        tasks.Add(Task.Run(async () =&gt;
        {
            //simulate some work...
            await Task.Delay(50);
            Console.WriteLine($&quot;index: {index}&quot;);
        }));
    }
    await Task.WhenAll(tasks);
}

The result:

> index: 0
> index: 1

Note that the sequence of the output is entirely dependent on the scheduling of the individual Tasks and cannot be predicted...

Useful reference: https://stackoverflow.com/questions/428617/what-are-closures-in-net

huangapple
  • 本文由 发表于 2023年6月2日 12:30:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76387117.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定