我可以并行进行多少次异步调用

时间:2015-03-26 06:30:20

标签: c# asp.net async-await

在我的申请中

int numberOfTimes = 1; //Or 100, or 100000

//Incorrect, please see update.
var tasks = Enumerable.Repeat(
                (new HttpClient()).GetStringAsync("http://www.someurl.com")
            , numberOfTimes);

var resultArray = await Task.WhenAll(tasks);

使用numberOfTimes == 1,需要5秒钟。

使用numberOfTimes == 100000,仍需要5秒钟。

太奇怪了。

但这是否意味着我可以并行运行无限制的呼叫?当它开始排队时必须有一些限制吗?

那是什么限制?那套在哪里?它取决于什么?

换句话说,有多少个IO完成端口?谁都在争夺他们? IIS是否拥有自己的IO完成端口集。

- 这是在ASP.Net MVC操作,.Net 4.5.2,IIS

<击>

更新:感谢@Enigmativity,以下与问题

更相关
var tasks = Enumerable.Range(1, numberOfTimes ).Select(i => 
           (new HttpClient()).GetStringAsync("http://deletewhenever.com/api/default"));

var resultArray = await Task.WhenAll(tasks);

使用numberOfTimes == 1,需要5秒钟。

使用numberOfTimes == 100,它仍需要5秒钟。

我现在看到更多可信的数字用于更高的数量。问题仍然存在,这个数字是什么?

2 个答案:

答案 0 :(得分:3)

这是一个测试,看看发生了什么。

从这段代码开始:

var i = 0;
Func<int> generate = () =>
{
    Thread.Sleep(1000);
    return i++;
};

现在打电话给:

Enumerable.Repeat(generate(), 5)

一秒钟后,您获得{ 0, 0, 0, 0, 0 }

但请拨打电话:

Enumerable.Range(0, 5).Select(n => generate())

五秒钟后,您获得{ 0, 1, 2, 3, 4 }

它只在代码中调用一次异步函数。

答案 1 :(得分:3)

  

那是什么限制?那套在哪里?

没有明确的限制。但是,您最终将耗尽资源。 Mark Russinovich有一个有趣的blog series on probing the limits of common resources

异步操作通常会增加内存使用量以换取响应能力。因此,每个自然异步操作至少使用内存用于其TaskOVERLAPPED结构和驱动程序的IRP(每个都表示在不同级别的正在进行的异步操作)。在较低级别,有很多不同的限制可以起到影响系统资源的作用(例如,我有一篇旧的博客文章,我had to calculate the maximum size of an I/O buffer - 你会认为这很简单,但实际上是不是)。

套接字操作需要一个客户端端口,它(理论上)限制为与同一远程IP的64k连接。套接字也有自己更大的内存开销,在设备级和用户空间都有输入和输出缓冲区。

在操作完成之前,IOCP不会发挥作用。在.NET上,您的AppDomain只有一个IOCP。在现代(4.5).NET框架上,为此IOCP提供服务的默认最大I / O线程数为1000。请注意,这是对一次可以完成的操作数量的限制,而不是一次正在进行中的数量