Ead*_*del 16 .net c# asp.net multithreading async-await
我需要从C#Web应用程序向服务发布一些数据.用户使用应用程序时会收集数据本身(一种使用情况统计信息).我不希望在每个用户的请求期间向服务发送数据,我宁愿在应用程序中收集数据,然后在一个单独的线程中发送单个请求中的所有数据,这不会满足用户的请求(我的意思是用户不必等待服务处理请求).为此,我需要一种JS的setInterval模拟 - 每隔X秒启动一次函数,将所有收集的数据刷新到服务中.
我发现Timer该类提供了一些类似的(Elapsed事件).但是,这允许只运行一次方法,但这不是一个大问题.它的主要困难是需要签名
void MethodName(object e, ElapsedEventArgs args)
Run Code Online (Sandbox Code Playgroud)
虽然我想启动异步方法,它将调用web服务(输入参数并不重要):
async Task MethodName(object e, ElapsedEventArgs args)
Run Code Online (Sandbox Code Playgroud)
任何人都可以建议如何解决所描述的任务?任何提示赞赏.
The*_*ias 27
这是一个以周期性方式调用异步方法的方法:
public static async Task PeriodicAsync(Func<Task> action, TimeSpan interval,
CancellationToken cancellationToken = default)
{
while (true)
{
Task delayTask = Task.Delay(interval, cancellationToken);
await action();
await delayTask;
}
}
Run Code Online (Sandbox Code Playgroud)
每隔调用action一次提供的interval,然后Task等待创建的。等待的持续时间不会影响间隔,除非它恰好比该时间长。在这种情况下,不重叠执行的原则优先,因此该时间段将延长以匹配等待的持续时间。
如果出现异常,PeriodicAsync任务将失败完成,因此如果您希望它能够容错,您应该在action.
使用示例:
Task statisticsUploader = PeriodicAsync(async () =>
{
try
{
await UploadStatisticsAsync();
}
catch (Exception ex)
{
// Log the exception
}
}, TimeSpan.FromMinutes(5));
Run Code Online (Sandbox Code Playgroud)
.NET 6 更新:现在可以Task.Delay通过使用新PeriodicTimer类来实现几乎相同的功能,而无需在每个循环上产生分配成本:
public static async Task PeriodicAsync(Func<Task> action, TimeSpan interval,
CancellationToken cancellationToken = default)
{
using PeriodicTimer timer = new(interval);
while (true)
{
await action();
await timer.WaitForNextTickAsync(cancellationToken);
}
}
Run Code Online (Sandbox Code Playgroud)
该WaitForNextTickAsync方法返回 a ValueTask<bool>,这使得该实现更加高效。但效率上的差异非常微小。对于每 5 分钟运行一次的定期操作,在每次迭代中分配一些轻量级对象的影响实际上应该为零。
基于 - 的实现的行为PeriodicTimer与基于 - 的实现不同Task.Delay。如果某个操作的持续时间长于interval,则两个实现都将在前一个操作完成后立即调用下一个操作,但PeriodicTimer基于 的实现的调度程序不会像Task.Delay基于 的实现那样向前滑动。请参阅下面的大理石图以直观地展示差异:
public static async Task PeriodicAsync(Func<Task> action, TimeSpan interval,
CancellationToken cancellationToken = default)
{
while (true)
{
Task delayTask = Task.Delay(interval, cancellationToken);
await action();
await delayTask;
}
}
Run Code Online (Sandbox Code Playgroud)
基于 的实现的调度Task.Delay永久向前移动,因为第三次调用 的action持续时间比interval.
正如您所看到的,PeriodicTimer并不能保证调用之间的最小间隔action。
出于教育目的,上述实现PeriodicAsync故意保持简单。诸如参数验证之类的事情ConfigureAwait已被省略。
i3a*_*non 24
的async当量是一个while带环Task.Delay(其在内部使用System.Threading.Timer):
public async Task PeriodicFooAsync(TimeSpan interval, CancellationToken cancellationToken)
{
while (true)
{
await FooAsync();
await Task.Delay(interval, cancellationToken)
}
}
Run Code Online (Sandbox Code Playgroud)
传递一个CancellationToken很重要,这样你可以在需要时停止该操作(例如当你关闭你的应用程序时).
现在,虽然这通常与.Net相关,但在ASP.Net中,做任何类型的火灾都会很危险.有几个解决方案(如HangFire),其中一些记录在Spark 和Forget on ASP.NET上由Stephen Cleary撰写,其他人在如何在ASP.NET中运行后台任务由Scott Hanselman
简单的方法是使用Tasks和一个简单的循环:
public async Task StartTimer(CancellationToken cancellationToken)
{
await Task.Run(async () =>
{
while (true)
{
DoSomething();
await Task.Delay(10000, cancellationToken);
if (cancellationToken.IsCancellationRequested)
break;
}
});
}
Run Code Online (Sandbox Code Playgroud)
当您要停止线程时,只需中止令牌:
cancellationToken.Cancel();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
30207 次 |
| 最近记录: |