【问题标题】:Delay in ContinueWith not working继续延迟不工作
【发布时间】:2018-08-06 00:55:08
【问题描述】:

我的问题是为什么延迟方法不起作用(整个操作没有等待 4 秒)并且 60% 没有显示在标签 1 中。

更准确地说,操作的顺序应该是这样的,整个操作应该需要 8 秒。但是需要 4 秒,只是 Thread.Sleep(4000) 里面的 LongTimeMethod1() 正在工作

LongTimeMethod1()//delay for 4 sec,show 60%
delay()//delay for 4 sec 
LongTimeMethod()//40% imidiatly

我知道我可以只使用 await 和 async 编写代码,但我想知道我在这段代码中做错了什么。

 private void button1_Click(object sender, EventArgs e)
    {
        CallBigMethod();
        label1.Text =@"Waiting ...";
    }
    private async void CallBigMethod()
    {
        var result = await BigMethod();
        label1.Text = result; 


    }
    private Task<string> BigMethod()
    {
        return Task.Factory
         .StartNew(() => LongTimeMethod1())
         .ContinueWith((pre) => Delay())
         .ContinueWith((pre) => LongTimeMethod());
    }     
    private string LongTimeMethod()
    {

        return  "40%...";
    }
    public async Task Delay()
    {

        await Task.Delay(4000);

    }
    private string LongTimeMethod1()
    {
        Thread.Sleep(4000);
        return "60%...";
    }  

【问题讨论】:

  • @PetSerAl 它只是解决了时间问题,但没有解决显示 60% 的问题

标签: c# multithreading async-await


【解决方案1】:

.ContinueWith((pre) =&gt; Delay()) 返回的Task 实际上是一个Task&lt;Task&gt;。该延续将在它完成开始延迟后立即完成,但由于延迟是异步的,它不会等待它完成。您需要解开 Task&lt;Task&gt; 的包装,以便为内部任务添加一个延续,并让您的程序在延迟结束时继续运行,而不是在它完成时启动

幸运的是,有一个 Unwrap 方法可以为我们完成所有这些工作。

private Task<string> BigMethod()
{
    return Task.Factory
     .StartNew(() => LongTimeMethod1())
     .ContinueWith((pre) => Delay())
     .Unwrap()
     .ContinueWith((pre) => LongTimeMethod());
}    

也就是说,当方法是async而不是使用ContinueWith时,整个事情要简单得多:

private Task<string> BigMethod()
{
    await Task.Run(() => LongTimeMethod1());
    await Delay();
    return await Task.Run(() => LongTimeMethod());
} 

【讨论】:

  • 感谢代码,它解决了时间问题,需要 8 秒,但标签中仍然没有显示 60%
  • @E_N_Y 那是因为LongTimeMethod 返回 40%,而不是 60%。如果切换LongTimeMethodLongTimeMethod1 的位置,结果会发生变化。如果您为这些方法使用更有意义(或至少可区分)的名称,那么这可能会减少混乱。
  • 所以你的意思是我无法显示 60% 然后 4 秒延迟然后用这段代码打印 40%?!我知道如果我改变方法,我可以得到不同的结果:)
  • @E_N_Y 不是你的结构方式。你可以用不同的方式构建你的代码来做到这一点。到那时,您将不再只计算结果。如果您尝试使用操作的当前进度更新 UI,那么您应该使用 Progress 类来执行此操作。让Task 返回的结果是操作的结果,而不是它的进度。
【解决方案2】:

试试这个

private Task<string> BigMethod()
    {

        return Task.Factory.StartNew(() => LongTimeMethod1()).ContinueWith(async (pre) => await Delay()).ContinueWith((pre) => LongTimeMethod());
    }

【讨论】:

  • 完全没有理由在ContinueWith 中使用async lambda。它什么也做不了。这与 OP 的代码相同。
猜你喜欢
  • 2011-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-02
  • 1970-01-01
  • 2018-10-29
  • 2019-06-01
  • 1970-01-01
相关资源
最近更新 更多