我认为您很有可能没有测试您认为正在测试的内容。据我所知,您正在尝试通过比较时间并推断线程注入来检测返回线程池的释放。
一方面,.NET 4.5 上线程池的默认设置非常高。您不会仅通过 10 或 100 个同时请求来击中他们。
退一步想想你想要测试什么:异步方法是否将其线程返回到线程池?
我有一个演示来演示这一点。我不想为我的演示创建重负载测试(在我的演示笔记本电脑上运行),因此我使用了一个小技巧:我人为地将线程池限制为更合理的值。
一旦你这样做了,你的测试就非常简单:执行那么多的并发连接,然后执行那么多的连接plus one。同步实现必须等待其中一个完成才能启动最后一个,而异步实现将能够启动所有这些。
在服务器端,首先将线程池线程限制为系统中处理器的数量:
protected void Application_Start()
{
int workerThreads, ioThreads;
ThreadPool.GetMaxThreads(out workerThreads, out ioThreads);
ThreadPool.SetMaxThreads(Environment.ProcessorCount, ioThreads);
...
}
然后进行同步和异步实现:
public class ValuesController : ApiController
{
// Synchronous
public IEnumerable<string> Get()
{
Thread.Sleep(1000);
return new string[] { "value1", "value2" };
}
// Asynchronous
public async Task<IEnumerable<string>> Get(int id)
{
await Task.Delay(1000);
return new string[] { "value1", "value2" };
}
}
最后是客户端测试代码:
static void Main(string[] args)
{
try
{
MainAsync().Wait();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
static async Task MainAsync()
{
ServicePointManager.DefaultConnectionLimit = int.MaxValue;
var sw = new Stopwatch();
var client = new HttpClient();
var connections = Environment.ProcessorCount;
var url = "http://localhost:35697/api/values/";
await client.GetStringAsync(url); // warmup
sw.Start();
await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
sw.Stop();
Console.WriteLine("Synchronous time for " + connections + " connections: " + sw.Elapsed);
connections = Environment.ProcessorCount + 1;
await client.GetStringAsync(url); // warmup
sw.Restart();
await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
sw.Stop();
Console.WriteLine("Synchronous time for " + connections + " connections: " + sw.Elapsed);
url += "13";
connections = Environment.ProcessorCount;
await client.GetStringAsync(url); // warmup
sw.Restart();
await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
sw.Stop();
Console.WriteLine("Asynchronous time for " + connections + " connections: " + sw.Elapsed);
connections = Environment.ProcessorCount + 1;
await client.GetStringAsync(url); // warmup
sw.Restart();
await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
sw.Stop();
Console.WriteLine("Asynchronous time for " + connections + " connections: " + sw.Elapsed);
}
在我的(8 个逻辑核心)机器上,我看到如下输出:
Synchronous time for 8 connections: 00:00:01.0194025
Synchronous time for 9 connections: 00:00:02.0362007
Asynchronous time for 8 connections: 00:00:01.0413737
Asynchronous time for 9 connections: 00:00:01.0238674
这清楚地表明异步方法正在将其线程返回到线程池。