【发布时间】:2018-07-09 15:09:28
【问题描述】:
这可能不是专门针对 SemaphoreSlim,但基本上我的问题是关于以下两种限制长时间运行任务集合的方法之间是否存在差异,如果是,那么差异是什么(以及何时有使用任何一个)。
在下面的示例中,假设每个跟踪的任务都涉及从 Url 加载数据(完全是虚构的示例,但这是我在 SemaphoreSlim 示例中找到的常见示例)。
主要区别在于如何将单个任务添加到跟踪任务列表中。在第一个示例中,我们使用 lambda 调用 Task.Run(),而在第二个示例中,我们使用 lambda 新建一个 Func(<Task<Result>>()),然后立即调用该 func 并将结果添加到跟踪的任务列表中。
示例:
使用Task.Run():
SemaphoreSlim ss = new SemaphoreSlim(_concurrentTasks);
List<string> urls = ImportUrlsFromSource();
List<Task<Result>> trackedTasks = new List<Task<Result>>();
foreach (var item in urls)
{
await ss.WaitAsync().ConfigureAwait(false);
trackedTasks.Add(Task.Run(async () =>
{
try
{
return await ProcessUrl(item);
}
catch (Exception e)
{
_log.Error($"logging some stuff");
throw;
}
finally
{
ss.Release();
}
}));
}
var results = await Task.WhenAll(trackedTasks);
使用新的函数:
SemaphoreSlim ss = new SemaphoreSlim(_concurrentTasks);
List<string> urls = ImportUrlsFromSource();
List<Task<Result>> trackedTasks = new List<Task<Result>>();
foreach (var item in urls)
{
trackedTasks.Add(new Func<Task<Result>>(async () =>
{
await ss.WaitAsync().ConfigureAwait(false);
try
{
return await ProcessUrl(item);
}
catch (Exception e)
{
_log.Error($"logging some stuff");
throw;
}
finally
{
ss.Release();
}
})());
}
var results = await Task.WhenAll(trackedTasks);
【问题讨论】:
-
不重新发明轮子而只使用 PLinQ:
var results = urls.AsParallel().WithDegreeOfParallelism(_concurrentTasks).Select(SyncDownLoadMethod).ToList()可能会容易得多。 -
很公平。但我仍然对这里的基本问题感到好奇——这些示例的工作方式的实际区别是什么?
标签: c# asynchronous async-await task