尽管被声明为异步,但任务被同步调用

时间:2016-06-03 18:12:13

标签: c# multithreading

请考虑以下代码:

public async static Task<bool> Sleeper(int sleepTime)
{
    Console.WriteLine("Sleeping for " + sleepTime + " seconds");
    System.Threading.Thread.Sleep(1000 * sleepTime);
    return true;
}

static void Main(string[] args)
{
    Random rnd = new Random();

    List<Task<bool>> tasks = new List<Task<bool>>();

    Console.WriteLine("Kicking off tasks");

    for (int i = 0; i < 3; i++)
    {
        tasks.Add(Sleeper(rnd.Next(10, 15)));
    }

    Console.WriteLine("All tasks launched");

    Task.WhenAll(tasks);


    int nComplete = 0;
    foreach (var task in tasks)
    {
        if (task.Result)
            nComplete++;
    }

    Console.WriteLine(nComplete + " Successful tasks");


}

每项任务应该随机休息一段时间(10-15秒之间)。但是我的输出如下所示

Kicking off tasks
Sleeping for 12 seconds
Sleeping for 14 seconds
Sleeping for 12 seconds
All tasks launched
3 Successful tasks

每个&#34;任务&#34;显然等待上一个任务在开始之前完成(我在调试和单步执行代码时也看到了这个),为什么会这样?

编辑很多人都提到使用Task.Delay按预期工作。但是,如果我没有做任何像睡觉,只做很多工作的事情。考虑一个大的无所事事的循环

int s = 1;
for (int i = 0; i < 100000000000000; i++)
      s *= i;

这仍然是同步执行

3 个答案:

答案 0 :(得分:1)

async并不意味着“在另一个线程上运行”。 Stephen Toub的博客详细介绍了一些内容,但当前的SynchronizationContext和执行的操作决定了一个任务是否以及何时在一个单独的线程上运行。在您的情况下,Thread.Sleep不会明确地在不同的线程上运行任何内容,因此它不会。

如果您使用await Task.Delay(1000 + sleepTime)代替Thread.Sleep,我认为您会发现事情按预期工作,因为Task.Delay已插入async / await基础架构,而{{1不是。

答案 1 :(得分:1)

这是因为您正在使用Thread.Sleep正在休眠调用Thread.Sleep的线程。 Sleeper方法从调用它们的线程开始,因此您正在睡眠主应用程序线程。

在异步代码中,您应该使用async,如下所示:

Task.Delay

答案 2 :(得分:0)

async并不意味着“在另一个线程上运行”。我有async intro详细了解了async 的含义。

实际上,Sleeper会生成编译器警告,通知您它将同步运行 。对所有新项目打开“警告为错误”是个好主意。

如果您要进行CPU绑定工作,可以在线程池线程上运行它,并使用await Task.Run异步等待它完成:

public static bool Sleeper(int sleepTime);

...

for (int i = 0; i < 3; i++)
{
  var sleepTime = rnd.Next(10, 15);
  tasks.Add(Task.run(() => Sleeper(sleepTime)));
}