在C#中的循环中使用Lambda表达式启动任务 [英] starting tasks with lambda expressions in loops in C#

查看:253
本文介绍了在C#中的循环中使用Lambda表达式启动任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在准备大学的C#考试时,我发现了以下多项选择题:

In the preparation for a C# exam at university I found the following multiple choice question:

客户端应用程序通过传递一组操作来调用您的库 去表演.您的图书馆必须确保系统资源最多 有效地使用.可以按任何顺序安排作业,但是您的 库必须记录每个操作的位置.您已经声明了这一点 代码:

Client applications call your library by passing a set of operations to perform. Your library must ensure that system resources are most effectively used. Jobs may be scheduled in any order, but your librarymust log the position of each operation. You have declared this code:

public IEnumerable<Task> Execute(Action[] jobs)
{
  var tasks = new Task[jobs.Length];

  for (var i = 0; i < jobs.Length; i++)
  {
      /* COMPLETION NEEDED */
  }

  return tasks;
}

public void RunJob(Action job, int index)
{
  // implementation omitted
}

通过在f​​or循环中插入代码来完成该方法.选择 正确答案.

Complete the method by inserting code in the for loop. Choose the correct answer.

1.)
tasks[i] = new Task((idx) => RunJob(jobs[(int)idx], (int)idx), i);
tasks[i].Start();

2.)
tasks[i] = new Task(() => RunJob(jobs[i], i));
tasks[i].Start();

3.)
tasks[i] = Task.Run(() => RunJob(jobs[i], i));

我选择了答案3,因为Task.Run()将指定的工作在线程池中排队,并返回代表该工作的Task对象.

I have opted for answer 3 since Task.Run() queues the specified work on the thread pool and returns a Task object that represents the work.

但是正确的答案是1,使用

But the correct answer was 1, using the Task(Action, Object) constructor. The explanation says the following:

在答案1中,构造函数的第二个参数作为 动作委托的唯一参数.当前值 将值装箱并传递给Task时,将捕获i变量 构造函数.

In answer 1, the second argument to the constructor is passed as the only argument to the Action delegate. The current value of the i variable is captured when the value is boxed and passed to the Task constructor.

答案2和3使用可捕获i变量的lambda表达式 从封闭的方法. Lambda表达式可能会返回 i的最终值,在这种情况下为10,在操作系统之前 抢占当前线程并开始由创建的每个任务委托 循环.无法确定确切的值,因为操作系统 根据您外部的许多因素安排线程执行 程序.

Answer 2 and 3 use a lambda expression that captures the i variable from the enclosing method. The lambda expression will probably return the final value of i, in this case 10, before the operating system preempts the current thread and begins every task delegate created by the loop. The exact value cannot be determined because the OS schedules thread execution based on many factors external to your program.

虽然我完全理解答案1的解释,但我对答案2和3的解释却不明白.为什么lambda表达式会返回最终值?

While I perfectly understand the explanation of answer 1, I don't get the point in the explanations for answer 2 and 3. Why would the lambda expression return the final value?

推荐答案

在选项2和3中,lambda捕获for循环中使用的原始i变量.无法保证何时在线程池上运行任务.可能的行为是:for循环结束,i=10,然后开始执行任务.因此,他们所有人都将使用i=10.

In options 2 and 3 lambda captures original i variable used in for loop. It's not guaranteed when tasks will be run on thread pool. So possible behavior: for loop is finished, i=10 and then tasks are started to execute. So all of them will use i=10.

类似的行为,您可以在这里看到:

Similar behavior you can see here:

void Do()
{
    var actions = new List<Action>();
    for (int i = 0; i < 3; i++)
    {
        actions.Add(() => Console.WriteLine(i));
    }

    //actions executed after loop is finished
    foreach(var a in actions)
    {
        a();
    }
}

输出为:

3
3
3

您可以这样解决它:

for (int i = 0; i < 3; i++)
{
    var local = i;
    actions.Add(() => Console.WriteLine(local));
}

这篇关于在C#中的循环中使用Lambda表达式启动任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆