.net 定期运行任务而不阻塞主线程C#

j13ufse2  于 2023-02-17  发布在  .NET
关注(0)|答案(3)|浏览(230)

我尝试每隔30分钟发送一个keep-alive HTTP请求,但是在这期间我还有其他方法要调用,所以我尝试做的是:

Task.Factory.StartNew(async () =>
{
    while(true){
        await Task.Delay(new TimeSpan(0,30,0), CancellationToken.None);
        await FooTask();
    }
});

我用得对吗?

kwvwclae

kwvwclae1#

你做得对吗?不对。你说你想要一个循环,但是你没有写一个循环。你还使用了错误的任务创建函数:

Task.Run(async () =>
{
    while(true)
    {
        await FooTask().ConfigureAwait(false);
        await Task.Delay(new TimeSpan(0, 30, 0)).ConfigureAwait(false);
    }
});

还有PeriodicTimer,它遵循类似的模式,你做你的动作,await做下一个滴答。

z9gpfhce

z9gpfhce2#

我建议使用微软的React式框架。
然后你可以这样做:

IDisposable subscription =
    Observable
        .Timer(TimeSpan.Zero, TimeSpan.FromMinutes(30.0))
        .SelectMany(_ => Observable.FromAsync(() => FooTask()))
        .Subscribe();

调用subscription.Dispose()就可以关闭它,很简单。

bejyjqdl

bejyjqdl3#

根据文档中的注解,您可能希望使用Task.Run()而不是Task.Factory.StartNewAsync()。除非您需要Task.Factory.StartNewAsync()中的额外选项(例如:任务创建选项、任务调度程序、Task.Run()未涵盖的参数传递)。
Task.Run()将任务排队,以便在当前线程池上运行,并且它还将返回任务的句柄,以防您希望等待完成或取消任务,如下例所示。

CancellationTokenSource src = new CancellationTokenSource();
CancellationToken ct = src.Token;
Task t = Task.Run(async () =>
{
    while(true){
        ct.ThrowIfCancellationRequested();
        await Task.Delay(new TimeSpan(0,30,0), ct);
        await FooTask();
    }
}, ct);

// Do some other stuff while your task runs

// Cancel Your Task, OR
ct.Cancel();

// Wait for your task to finish
try
{
    t.Wait();
}
catch (AggregateException e)
{
    // Handle the exception
}

相关问题