【问题标题】:Declaring a Task Property and awaiting it声明一个任务属性并等待它
【发布时间】:2017-03-29 14:37:46
【问题描述】:

我被一些我认为很简单的事情困住了,它把我逼疯了。

我需要在某个时候声明一个任务并稍后运行它,我想到了:

Task T1 { get; set; }

public async Task CreateAndAwaitAsync()
{
    T1 = new Task(() => {
        // time consuming work like:
        System.Threading.Thread.Sleep(1000);
    }

    await T1;
}

当然 lambda 的主体和方法只是为了这个示例(正如我所说的我需要稍后运行它),但无论如何,使用 await T1 我无法进入 lambda !我错过了什么??我觉得自己很愚蠢,因为我已经使用 async-await 范式已经好几年了,我什至没有想到这不起作用!

【问题讨论】:

  • 你错过了开始你的任务。 await 不会为您启动它。如果您不想启动它 - 只是不要等待它 - 按原样返回(并从方法中删除 async 关键字)。
  • 不要使用Task 构造函数。如果您只是想排队 CPU 密集型工作,请使用 T1 = Task.Run(() => ....
  • @JSteward 我不能,因为这样任务马上就开始了!我需要在另一个时间和另一个地方开始它,而不是我声明它的时间和地点,它在帖子中指定。

标签: c# .net asynchronous lambda async-await


【解决方案1】:

我认为可以在评论中回答,但最好提供更多信息。

await 的意思是“等待这个任务完成,然后做剩下的事情”。您的示例中的任务未启动。 await 不会为您启动它,因此整个方法将停留在 await 直到您启动任务。

即使使用您当前的代码,如果您稍后执行 T1.Start() - 它将运行您的 lambda,并且在完成后 - 您由 CreateAndAwaitAsync 返回的任务也将完成。

否则 - 要么在创建任务时立即启动它 (Task.Run),要么直接返回 Task 而无需任何 async\await:

public Task CreateAndAwaitAsync()
{
    T1 = new Task(() => {
        // time consuming work like:
        System.Threading.Thread.Sleep(1000);
    }
    // if you need to start it somewhere, do T1.Start();
    return T1;
}

【讨论】:

  • 完美...所以无论我需要在哪里开始任务,我都需要先调用Start,然后再调用await!明白了!谢谢!
  • 请注意,在您提供的代码中,没有理由等待任务 - 只需从方法中返回即可。当然,如果您在现实中有更复杂的代码 - 情况可能会有所不同。
  • 当然但是就像我说的那样,那是为了示例......任务的await将在另一个函数中完成,在另一个时刻
【解决方案2】:

就像@Evk 说的,你需要调用 T1.Start()

public async Task CreateAndAwaitAsync()
    {
        T1 = new Task(() =>
        {
            // time consuming work like:
            System.Threading.Thread.Sleep(1000);
        });

        T1.Start();
        await T1;
    }

【讨论】:

  • 完美!谢谢!
【解决方案3】:

你没有开始任务。

例子:

public async Task DoSomething()
{
    await Task.Run(() => SomeMethod());
}

【讨论】:

  • 我需要将任务分配给一个属性以便稍后调用它
  • 不管怎样,你还是需要运行/启动任务。
  • 对,就在await之前
【解决方案4】:

您只是创建了一个Task,但即使在此处使用await,它也没有运行。尝试Start()它,或者你可以分配T1 = Task.Run(your => lambda),然后它应该在你等待它时工作

【讨论】:

  • 使用Task.Run,任务的动作被安排为立即执行,但我需要在稍后调用await T1 时执行它(不是我拒绝你)
  • @Shockwaver 然而你的问题并没有说明这一点。无论如何,您都在等待它,而不是等待一段时间。
  • @Servy 是的,我做了,请阅读帖子的第二行。最后再读一遍:这只是一个例子。
  • @Servy 是的,稍后意味着稍后......当我用Task.Run 声明它时肯定不是,你不这么认为吗? ;) 来吧... XD 'When' 无关紧要,因为 'Later' 已经将它推离了声明的时间...
  • 来吧伙计们,如果您真的需要讨论这个问题,请在聊天中进行扩展讨论。
【解决方案5】:

除非您正在执行 CPU 密集型工作,否则您几乎不需要调用 Task.Run,​​而是可以使用 async/await,例如:

  public async Task DelayMe()
  {
    await Task.Delay(1000);
    await MoreAsyncThings();
  }

  Task T1 { get; set; }

  public async Task CreateAndAwaitAsync()
  {
    T1 = DelayMe();
    await T1;
  }

更新:

为了存储代码以供以后执行,我建议简单地使用如下 lambda:

Func<Task> SomeWorkFactory()
{
  return async () => 
  { 
    await AsyncStuff(); 
    // More Stuff 
  };
}

var deferedWork = SomeWorkFactory();

// later somewhere else

await deferedWork(); 

所以基本上调用“SomeWorkFactory”会创建工作包,但只调用 Func 会执行它并返回一个等待的任务。

可能相关:

如果您提供的方法执行 CPU 密集型工作(例如计算某些东西而不是等待回调),您根本不应该提供异步签名,而是将执行模式留给调用者。主要是因为异步和并发是不同的概念。 Mads Torgersen 在这里给出了一些见解:https://channel9.msdn.com/Events/TechEd/NorthAmerica/2014/DEV-B362 并称之为“库方法不应该撒谎”(从第 42 分钟开始)

【讨论】:

  • 我无法预测 MoreAsyncThings 将排队到有问题的任务中,所以它必须是一个独立的 entity,我可以在其他地方定义的调用者中排队,而谁知道其他工作完成
  • 我认为我没有完全理解您的整体问题。如果您想稍后执行一些代码,最好将其存储为 lambda 函数,而不是存储在“完整的”任务中。我将更新上面的代码示例。
  • 再来一次!那个例子只是一个例子!!刚刚开始任务!我的 prop 已经是一个 lambda,当我想开始任务时我会调用它,但我让示例尽可能简单,让您专注于我遇到的问题,而不是优化我的代码。问题很简单:为什么我的await 没有开始我创建的任务? (我不需要指定我通过编译 func lambda 来获得该任务!你不需要知道它!)。 Evk 几乎立即回答:“因为你是一只愚蠢的猴子:你的await 并没有神奇地为你启动Task,你必须先.Start 它!”。不错!
  • 我的问题完美地描述了“整体问题”,我会引用自己的话:“无论如何,使用 await T1 我就是无法进入 lambda!我错过了什么??” /跨度>
猜你喜欢
  • 2020-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-02
  • 1970-01-01
相关资源
最近更新 更多