Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ms-access/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步方法中不等待任务的注意事项_C#_.net_Async Await_Task Parallel Library_Fire And Forget - Fatal编程技术网

C# 异步方法中不等待任务的注意事项

C# 异步方法中不等待任务的注意事项,c#,.net,async-await,task-parallel-library,fire-and-forget,C#,.net,Async Await,Task Parallel Library,Fire And Forget,我正在从事一个Web API项目,该项目使用Azure的托管缓存服务将数据库结果缓存在内存中,以提高响应时间并减少数据库的重复流量。尝试将新项目放入缓存时,偶尔会引发特定于缓存的异常,代码为DataCacheErrorCode.RetryLater。当然,为了稍后重试而不需要阻塞此方法,我将其设置为async和wait Task.Delay稍后重试。以前,一个开发人员硬编码了一个线程。其中的Sleep会严重影响应用程序的性能 方法签名现在看起来与此类似: public static async

我正在从事一个Web API项目,该项目使用Azure的托管缓存服务将数据库结果缓存在内存中,以提高响应时间并减少数据库的重复流量。尝试将新项目放入缓存时,偶尔会引发特定于缓存的异常,代码为
DataCacheErrorCode.RetryLater
。当然,为了稍后重试而不需要阻塞此方法,我将其设置为
async
wait Task.Delay
稍后重试。以前,一个开发人员硬编码了一个
线程。其中的Sleep
会严重影响应用程序的性能

方法签名现在看起来与此类似:

public static async Task Put(string cacheKey, object obj)
在此更改之后,我从调用以前同步版本的
Put
的应用程序中的所有其他位置收到约75条编译器警告,指示:

因为不等待此调用,所以当前方法的执行将在调用完成之前继续。考虑将“Acess”运算符应用到调用的结果。< /P>
在这种情况下,由于
Put
不返回任何内容,因此我认为让此操作触发并忘记是有意义的,因为我看不到任何理由阻止调用它的方法的执行。我只是想知道,如果允许大量这样的火灾并忘记在后台运行的
Task
s,因为可以经常调用
Put
,是否存在任何危险或陷阱。或者我应该等待,因为99%的时间我不会得到重试错误,
任务
几乎会立即完成。我只是想确保我不会因为线程太多(或类似的事情)而受到任何惩罚。

警告告诉您,在一个您可能不想实际触发并忘记的位置,您正在发生触发并忘记行为。如果您真的想触发并忘记,并且在不知道操作何时完成或操作是否成功完成的情况下没有问题继续,那么您可以安全地忽略该警告。

如果有机会
Put
将出于任何原因引发任何其他异常,而且,每次向缓存中插入对象时,都不会使用
await Put
,异常将被包含在返回的
任务中,而该任务未被等待。如果您使用的是.NET 4.0,此异常将在该
任务的终结器中重新抛出。
。如果您使用的是.NET4.5,它将被忽略(这可能不可取)

想确保我不会因为吃太多而受到任何惩罚吗 很多线或者类似的东西


我这么说只是想把事情弄清楚。使用
Task.Delay
时,不会旋转任何新线程。
任务
并不总是等于正在旋转的新线程。特别是在这里,
Task.Delay
在内部使用了一个
计时器
,因此没有任何线程开销(如果使用
wait
,则当前正在延迟的线程除外)。

建议使用ASP.NET方式

HostingEnvironment.QueueBackgroundWorkItem(WorkItem);

...

async Task WorkItem(CancellationToken cancellationToken)
{
    try { await ...} catch (Exception e) { ... }
}

顺便说一句,在ASP.NET线程以外的线程上不捕获/重新抛出会导致服务器进程崩溃/重新启动

释放未等待运行的任务的一个负面结果是编译器警告本身-75编译器警告本身是一个问题,它们隐藏了真正的警告

如果您想向编译器发出信号,表明您有意不对任务的结果执行任何操作,那么可以使用一个简单的扩展方法,该方法不执行任何操作,但满足编译器对明确性的要求

// Do nothing.
public static void Release(this Task task)
{
}
现在你可以打电话了

UpdateCacheAsync(data).Release();
没有任何编译器警告


+1;将方法标记为显式“开火并忘记”可以将返回类型从async Task更改为async void。@alexm async void不能与Web API配合使用。我过去收到过一些异常,表明在尝试使用时不允许这样做it@alexm这样一来,调用该方法的唯一方法就是通过fire and forget,这不同于允许等待方法,而只是在某些情况下为某些调用方执行fire和forget语义。@Jesse Carter:你是对的,我只是建议如何消除警告。。不过,在不等待异步任务方法的情况下调用该方法也会产生同样的效果。@alexm well在编译器警告中权衡会破坏我的应用程序的异常,在这一点上似乎并不可取:P@alexm在运行处理程序的时间过后,它会在很短的时间内使用线程池线程。它在等待时不消耗线程池线程。这意味着线程只有在有生产性工作要做时才会被使用,这正是您想要(也无法避免)的。-Servy:再次,我同意您的说法,这就是为什么我用“技术上”一词的原因:)我不鼓励
等待任务。运行(…)
在ASP.NET上伪造
异步
处理程序,这是绝大多数尝试的
任务。运行
用法。唯一真正的
Run
用例是fire-and-forget。而且,99%的fire And forget ASP.NET场景不应该使用fire And forget。更新缓存是极少数可以接受触发和遗忘(以及
Task.Run
)的用例之一。关于请求上下文,我指的是该请求的
AspNetSynchronizationContext
,这是(正如我在博客上所描述的)。@StephenCleary没有使用
ConfiguareAwait(false)
而不是使用
任务。如果你只是想忽略上下文,请运行
。@YuvalItzchakov:大致相当。类似于
await Task.Yield().ConfigureAwait(false)
的内容将生成当前线程并在线程池线程上恢复该方法;而
Task.Run
将其委托排队到线程池。我认为
Task.Run
有更清晰的意图(代码