我正在做一些基準測試,使用一個簡單的C#控制檯應用程序編寫,使用C#5的async/await結構和數字不加起來(事實上它們合起來,這就是問題;))Benchmarking async await incomprehension
我是基準測試三種不同的場景: 1)20K調用SQL服務器存儲過程。 2)20K調用一個簡單的HTTP服務器 3)方案1)和2)一起
以下是有關方案的更多細節:
1)20K調用SQL存儲過程服務器。
在這種情況下,我調用外部SQL Server存儲過程20K次。 CallSqlStoredProcedureAsync方法使用ADO.NET異步方法(OpenAsync,ExecuteNonQueryAsync ...)。我甚至在方法入口處等待Task.Yield()以避免在到達異步點之前執行任何同步代碼,以避免在最短的時間內阻塞我的循環。
var tasks = new List<Task>();
for (int i=0; i<20000; i++)
{
tasks.Add(this.CallSqlStoredProcedureAsync());
}
Task.WhenAll(tasks).Wait();
這樣就完成了約10秒與CPU消耗平均爲70%。
2)20K調用一個簡單的HTTP服務器
在這種情況下我呼籲外部Web服務器使用的HttpClient的url和異步方法以及(PostAsync)。
for (int i=0; i<20000; i++)
{
tasks.Add(this.SendRequestToHttpServerAsync());
}
這樣就完成了約30秒與CPU消耗平均爲30%
3)方案1)和2)一起
for (int i=0; i<20000; i++)
{
tasks.Add(this.CallSqlStoredProcedureAsync());
tasks.Add(this.SendRequestToHttpServerAsync());
}
這樣就完成了約40秒,CPU消耗平均70%,持續約20秒,然後30秒,剩餘20秒。
現在的問題
我不明白爲什麼標杆正在40秒場景#3。如果執行是連續的,或者如果我的CPU(或I/O)對於方案1和方案2是100%,那麼我認爲這是正常的,具有方案1的時序+方案2的時序。
考慮到I我正在使用異步/等待結構完全異步,我期望的場景#3的目的是在30秒內完成(「鏈中最薄弱的環節」),即場景#2的持續時間。
有什麼我不明白在這裏:(
任何線索?
編輯:每@svick要求,這裏是基準的完整代碼(不包括一些無用的東西)
static void Main(string[] args)
{
var bench = new Bench();
while (true)
{
string iterationsAndScenario = Console.ReadLine();
var iterations = int.Parse(iterationsAndScenario.Split(' ')[0]);
var scenario = int.Parse(iterationsAndScenario.Split(' ')[1]);
var sw = new Stopwatch();
sw.Start();
bench.Start(iterations, scenario).Wait();
sw.Stop();
Console.WriteLine("Bench too {0} ms", sw.EllapsedMilliseconds);
}
}
public class Benchmark
{
public Task Start(int iterations, int scenario)
{
var tasks = new List<Task>();
if (scenario == 1)
{
for (int i=0; i<iterations; i++)
{
tasks.Add(this.CallSqlStoredProcedureAsync().ContinueWith(t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted));
}
}
else if (scenario == 2)
{
var httpClient = new HttpClient();
for (int i=0; i<iterations; i++)
{
tasks.Add(httpClient.PostAsync(uri, new StringContent("Hello")).ContinueWith(t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted));
}
}
else if (scenario == 3)
{
var httpClient = new HttpClient();
for (int i=0; i<iterations; i++)
{
tasks.Add(this.CallSqlStoredProcedureAsync().ContinueWith(t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted));
tasks.Add(httpClient.PostAsync(uri, new StringContent("Hello")).ContinueWith(t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted));
}
}
return Task.WhenAll(tasks);
}
public async Task CallSqlStoredProcedureAsync()
{
await Task.Yield();
using (var conn = new SqlConnection(connectionString))
{
using (var cmd = new SqlCommand("sp_mystoreproc", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@param1", 'A');
cmd.Parameters.AddWithValue("@param2", 'B');
await cmd.Connection.OpenAsync();
await cmd.ExecuteNonQueryAsync();
}
}
}
}
由於它使用線程池,是否達到工作線程數的默認限制,從而變得有效的順序?對於兩組並行運行的任務,它需要使可用線程翻倍。 – weston
給ThreadPool.SetMaxThreads一個去。可以讓它接近100%cpu – weston
你能發佈你的基準測試的完整代碼嗎?特別是兩種Async方法可能很重要。 – svick