gpt4 book ai didi

c# - 限制异步方法的并行度而不阻塞线程池线程

转载 作者:可可西里 更新时间:2023-11-01 08:46:14 29 4
gpt4 key购买 nike

我有一个异步方法 RequestInternalAsync()它向外部资源发出请求,并希望编写一个包装方法,通过减少并行性来限制对该方法的并发异步请求的数量。

想到的第一个选项是 TaskScheduler并发性有限(LimitedConcurrencyLevelTaskSchedulerConcurrentExclusiveSchedulerPair 等)。

但要使用自定义调度程序运行任务,我必须使用 TaskFactory 启动任务只接受 Action<> ,即我不能通过不阻塞额外的线程来等待内部方法的执行来做到这一点。

第二个选项是 SemaphoreSlim , 它完成了它的工作,但在这种情况下,我正在实现节流,而不是使用 TaskScheduler .

static void Main(string[] args)
{
// TESTING 1

var task1 = Task.WhenAll(Enumerable.Range(1, 10).Select(i => RequestAsyncBad()));

task1.Wait();

// TESTING 2

var task2 = Task.WhenAll(Enumerable.Range(1, 10).Select(i => RequestAsyncBetter()));

task2.Wait();
}

private static Task RequestInternalAsync()
{
return Task.Delay(500);
}

解决方案#1:

private static readonly ConcurrentExclusiveSchedulerPair _concurrentPair
= new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 2);

public static Task RequestAsyncBad()
{
// Dumb: Because TaskFactory doesn't provide an overload which accepts another task, only action.
// As result, we blocking a thread to just wait until the inner task finishes.

return Task.Factory.StartNew(() => RequestInternalAsync().Wait(),
CancellationToken.None, TaskCreationOptions.DenyChildAttach, _concurrentPair.ConcurrentScheduler);
}

解决方案 #2(更好):

private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(2);

public static async Task RequestAsyncBetter()
{
// Here we don't waste thread-pool thread on waiting for a completion of inner task,
// but instead of using TaskScheduler, implementing a hand-made stuff with semaphore.

await _semaphore.WaitAsync().ConfigureAwait(false);

try
{
await RequestInternalAsync();
}
finally
{
_semaphore.Release();
}
}

更优雅的方法是什么?

  • 重用标准Task TPL 的 API 和 TaskScheduler
  • 并且不阻塞额外的线程

最佳答案

TaskScheduler 仅对 CPU 密集型工作有用。您的工作没有使用线程。它使用 IO 完成端口,这意味着您的网络调用根本不包含任何线程。无法让 TaskScheduler 参与 IO 操作。

如果您还不确定:.NET 中的异步 IO 是基于使用 TaskCompletionSource 的,它丝毫没有绑定(bind)到线程或调度程序。

SemaphoreSlim 是正确的做法。或者,创建一个 ServicePoint 并设置其最大并发数。仅适用于 HTTP 请求。

请注意,如果您发现自己正在使用 Wait,您应该犹豫并考虑一下您在做什么。通常,这是一个错误。

关于c# - 限制异步方法的并行度而不阻塞线程池线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23550470/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com