如何在C#中使用延迟来执行Task.ContinueWith后续任务?

4

我知道我可以像这样执行一个简单的延迟任务:

Task.Delay(iDelayInMilliseconds).ContinueWith(() => SomeMethod());

我可以像这样将两种不同的方法链式地作为连续任务:

Task.Run(() => SomeMethod()).ContinueWith(() => AnotherMethod());

我无法理解的是像这样的内容:

Task.Run(() => SomeMethod()).Delay(iDelayInMilliseconds).ContinueWith(() => AnotherMethod());

有效地说,我希望SomeMethod()执行后延迟一段时间再执行AnotherMethod()。
有人能帮我吗?

1
在你的例子中,最好不要使用老式的ContinueWith,而是使用async/await。后者更易于阅读。 - user585968
如果您坚持使用ContinueWith,可以使用theTask.ContinueWith(t=>Thread.Sleep(iDelayInMilliseconds))来进行延迟。 - momvart
2个回答

4
Task.Run(async () =>
{
    SomeMethod();
    await Task.Delay(iDelayInMilliseconds);
}).ContinueWith(cw => AnotherMethod());

在这里,我们需要实际等待内部的任务(即Task.Delay(iDelayInMilliseconds)),否则由Task.Run()返回的任务会立即返回,并将其状态设置为RanToCompletion。 当然,如果不需要在ThreadPool线程上运行,则可以完全删除Task.Run():
// ...
SomeMethod();
await Task.Delay(iDelayInMilliseconds);
AnotherMethod();

这意味着您需要将父方法标记为async,并将其返回类型更改为Task<T>而不是T,如果它返回void,则返回Task


2
我建议您查看微软的响应式框架。在我看来,它比任务更强大,可以像LINQ查询一样使用,并且可以轻松地与任务和异步操作进行交互。
在您的情况下,您的代码可能如下所示:
void Main()
{
    var iDelayInMilliseconds = 4000;

    IObservable<int> query =
        from x in Observable.Start(() => SomeMethod())
        from y in Observable.Timer(TimeSpan.FromMilliseconds(iDelayInMilliseconds))
        from z in Observable.Start(() => AnotherMethod())
        select x + z;

    IDisposable subscription = query.Subscribe(w => Console.WriteLine(w));
}

public int SomeMethod() => 1;
public int AnotherMethod() => 2;

这需要 4,000 毫秒的时间,并在控制台上输出 3

如果你想提前停止查询,只需在 subscription 上调用 .Dispose()

如果你的一些方法是 async 的,并且想要返回一个 Task<int>,那么可以这样做:

void Main()
{
    var iDelayInMilliseconds = 4000;

    IObservable<int> query =
        from x in Observable.StartAsync(() => SomeMethod())
        from y in Observable.Timer(TimeSpan.FromMilliseconds(iDelayInMilliseconds))
        from z in Observable.Start(() => AnotherMethod())
        select x + z;

    Task<int> task = query.ToTask();

    Console.WriteLine(task.Result);
}

public async Task<int> SomeMethod() => await Task.Run(() => 1);
public int AnotherMethod() => 2;

使用正确的延迟,这仍然可以产生正确的结果。

只需使用NuGet获取 "System.Reactive" 并在您的代码中添加 using System.Reactive.Linq; 即可使其正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接