C# 为什么线程。睡眠有效,而任务。延迟无效?

C# 为什么线程。睡眠有效,而任务。延迟无效?,c#,.net,asynchronous,async-await,task,C#,.net,Asynchronous,Async Await,Task,在我的代码中,我假设outerFlag将在innerFlag之后被命中,但它实际上像火一样运行,忘记了innerFlag是在outerFlag之后被命中的。当我使用Thread.Sleep而不是Task.Delay标志时,会按正确的顺序命中 代码如下: [Test] public async Task Test() { bool innerFlag = false; bool outerFlag = false; await Lock(async () => {

在我的代码中,我假设outerFlag将在innerFlag之后被命中,但它实际上像火一样运行,忘记了innerFlag是在outerFlag之后被命中的。当我使用Thread.Sleep而不是Task.Delay标志时,会按正确的顺序命中

代码如下:

[Test]
public async Task Test() {

    bool innerFlag = false;
    bool outerFlag = false;

    await Lock(async () => {
        await Task.Delay(2000);
        innerFlag = true;
    });

    outerFlag = true;

    Thread.Sleep(1000);
    Thread.Sleep(2500);
}

private Task Lock(Action action) {
    return Task.Run(action);
}
我还注意到,当我调用Task.Delay并设置innerFlag时,没有使用锁方法,而是使用直接lambda,它可以按预期工作

有人能解释这种行为吗?

您的锁定方法不理解异步委托,因此您试图作为参数传递的异步委托被视为异步无效。异步空洞在各种方面都有问题,除非它们被用于预期用途,否则作为事件处理程序

要确保方法理解异步委托,必须创建一个接受Func作为参数的重载:

private Task Lock(Func<Task> func)
{
    return Task.Run(func);
}

请注意,func参数可以直接传递给,因为此方法也理解异步委托。并非所有的内置方法都理解异步委托,值得注意的例子有和。每次在委托中添加异步修饰符时都必须小心。您必须确保被调用的方法理解异步委托,否则可能会导致异步无效及其造成的破坏。

这是因为Lock接受委托,在您的情况下,该委托返回任务。但你们并没有等待那个任务,所以这是一个火和忘记的任务。基本上你只需要等待锁爆炸。。。委托内部的2秒延迟将等待,然后将innerFlag设置为true,但您已经忽略该任务并继续执行。如果将Lock更改为private async task LockFunc func{await func;},它可能会更好。这是否回答了您的问题?当然,它运行起来就像火和遗忘一样——你将一个任务返回方法传递给某个吃东西的动作,这意味着这样产生的任务被忽略。本质上,你得到的正是你想要的。请注意,如果您想要实际的锁定/排除,这显然不是,那么您需要使用信号量lim或-不要试图用您自己的布尔标志来重新设计轮子,因为这几乎肯定会遇到微妙的错误。@defaultlocale否,您的问题不能回答这个问题