【问题标题】:Why is my method not running asynchronously?为什么我的方法没有异步运行?
【发布时间】:2015-02-27 17:58:44
【问题描述】:

我正在运行一个应该多次调用一个方法而不等待其结果的测试。这是我的代码:

 private async Task HandleJob(string params) {
        // do stuff that takes a minute
        Thread.Sleep(10000);
        return;
 }

 [TestMethod]
 public async Task StartTest() {
     HandleJob("one");
     HandleJob("two");
 }

当我在HandleJob("two") 设置休息时,它只会在one 完成后才会被击中。如何让它们异步运行,不等待?

【问题讨论】:

  • 这些操作真的是异步的吗?
  • @YuvalItzchakov - 是 Selenium 驱动浏览器 - 我不认为他们是,但我希望他们是!
  • @SB2055:编译器会发出警告,告诉您问题所在以及如何解决。

标签: c# asp.net-mvc-4 asynchronous c#-5.0 async-await


【解决方案1】:

你根本没有在方法中使用await。这意味着该方法将同步执行这些行。要真正返回给调用者并让剩余的代码异步运行,您需要使用await,它将继续该方法作为目标Task 的延续(以及取消装箱任何异常和返回值)

Task 中有几个辅助方法可以帮助解决这个问题 - 我最喜欢的是 Task.Yield(),它会立即返回,因此 await Task.Yield() 会吐出到一个新线程中并立即返回。

[TestMethod]
public async Task StartTest() {
     await Task.Yield(); // await yields control, and Yield will ensure the rest of the method starts immediately
     HandleJob("one");
     HandleJob("two");
}

如果您希望单个子任务同时执行,请使用 Task.WhenAllTask.Run 将它们合并

[TestMethod]
public async Task StartTest() {
     await Task.WhenAll(
         Task.Run(() => HandleJob("one")),
         Task.Run(() => HandleJob("two")));
}

【讨论】:

  • 我不知道为什么这被否决了,当其他答案没有时它可以工作
【解决方案2】:

您的异步方法HandleJob 并不是真正的async,因为Thread.Sleep 阻塞了当前线程。尝试改用await Task.Delay。请注意,params 是一个关键字,您的原始代码将无法编译。我已将其更改为parameters

private async Task HandleJob(string parameters) {
        // do stuff that takes a minute
        await Task.Delay(10000);
        return;
 }

在您的 start 方法中,您可以返回一个 Task,当两个方法都使用 Task.WhenAll 完成时完成,正如其他答案之一所指出的那样。如果您返回结果而不是await 它,那么StartTest 的调用者可以确定他是否等待Task 完成,或者他是否忽略它并且它变成了火灾和忘记的情况。因为你没有使用awaitStartTest,所以不再需要标记为async

 [TestMethod]
public Task StartTest() {
     return Task.WhenAll(HandleJob("one"), HandleJob("two"));
 }

【讨论】:

    【解决方案3】:

    你需要await这两个任务:

        private void HandleJob( params string[] value )
        {
            return;
        }
    
        [TestMethod]
        public async Task StartTest()
        {
            var task1 = Task.Run( () => HandleJob( "one" ) );
            var task2 = Task.Run( () => HandleJob( "two" ) );
            await Task.WhenAll( task1 , task2 );
        }
    

    【讨论】:

    • 更好,但请注意new[] 不是必需的,因为WhenAll 方法是使用params 参数定义的
    • 谢谢!我以前没用过,所以不确定重载是什么:p
    • 谢谢!我试过这个,但是当我定义 task1... 时 HandleJob 正在运行,所以在完成之前我从不点击 task2。
    • 你应该返回一个 Task.Run(() => { } );
    猜你喜欢
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 1970-01-01
    • 2021-08-04
    • 1970-01-01
    • 2019-06-05
    • 1970-01-01
    相关资源
    最近更新 更多