/의 구조를 기다리고 C# 5와 숫자가 추가하지 않습니다 (물론 실제로 그들이까지 추가하고, 그게 문제입니다;))벤치마킹 비동기 await를 몰이해
나는 세 가지 시나리오를 벤치마킹하고 있습니다 : 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();
이 70 %의 CPU 소비 평균 약 10초에을 완료한다.
2) 20K는 내가 사용하여 외부 웹 서버에 URL을 HttpClient를하고 비동기 방법뿐만 아니라 (PostAsync)를 호출이 시나리오에서는 간단한 HTTP 서버
호출합니다.
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 소비는 약 20 초 동안 평균 70 %, 나머지 20 초 동안 평균 30 %입니다. 벤치 마크 시나리오 # 3 40 초 걸리는 이유를 이해하지 않는 질문
지금
. 실행이 순차적이거나 시나리오 1 및 2의 CPU (또는 I/O)가 100 % 인 경우 시나리오 1의 타이밍 + 시나리오 2의 타이밍을 갖는 것이 정상이라고 말할 수 있습니다.
async/await 구조를 사용하여 완전히 비동기식으로 진행 중이며, 시나리오 # 3에서 예상했던 것은 시나리오 # 2의 지속 시간 인 30 초 ("체인의 가장 약한 링크") 내에 완료해야한다는 것입니다.
뭔가 여기가 이해가 안되는 :(
어떤 단서?
편집 : @svick의 요청에 따라, 여기에 내가 더 빨리보다 DB 전체에 대한 쿼리를 추측, (일부 쓸모없는 물건 제외) 벤치 마크의 전체 코드
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
벤치 마크의 전체 코드를 게시 할 수 있습니까? 특히 두 개의 비동기 메소드가 중요 할 수 있습니다. – svick