나는 약 1,000 개의 작업을 실행할 필요가있다.ThreadPool
야간 기준으로 (그 숫자는 앞으로 커질 수 있음). 각 작업은 장기 실행 작업 (웹 서비스에서 데이터 읽기)을 수행하며CPU 집약적이지 않음.Async I/O
이 특정 사용 사례에 대한 옵션이 아닙니다.
주어진IList<string>
매개 변수 중DoSomething(string x)
. 다음 두 옵션 중 하나를 선택하려고합니다.
IList<Task> tasks = new List<Task>();
foreach (var p in parameters)
{
tasks.Add(Task.Factory.StartNew(() => DoSomething(p), TaskCreationOptions.LongRunning));
}
Task.WaitAll(tasks.ToArray());
또는
Parallel.ForEach(parameters, new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount*32}, DoSomething);
어떤 옵션이 더 좋고 그 이유는 무엇입니까?
노트 :
대답에는 사용법과TaskCreationOptions.LongRunning
과MaxDegreeOfParallelism = Environment.ProcessorCount * SomeConstant
.
아마 당신은이 사실을 모르고 있지만,Parallel
클래스는 단순히 (복잡한) 래퍼입니다.Task
사물. 궁금한 점이있는 경우Parallel
클래스는Task
~과 함께하는 물건TaskCreationOptions.None
. 그러나, 그MaxDegreeOfParallelism
작업 개체의 생성자에 전달 된 생성 옵션에 상관없이 이러한 작업 개체에 영향을줍니다.
TaskCreationOptions.LongRunning
근원에 "힌트"를 준다.TaskScheduler
스레드 초과 사용으로 성능이 향상 될 수 있습니다. Oversubscription은 대기 시간이 긴 스레드 (예 : I / O)에 적합합니다. 하나의 코어에 하나 이상의 스레드 (예 : 스레드가 아닌 작업)를 할당하므로 대기를 기다리지 않고 항상 할 일이 생기기 때문입니다 thread가 대기 상태의 동안 완료하는 조작. 에TaskScheduler
그 (것)들을 사용하는ThreadPool
, 그것의지LongRunning 작업을 자신의 전용 스레드 (작업 당 스레드가있는 유일한 경우)로 실행하십시오. 그렇지 않으면 스케줄링 및 작업 도용 (실제로는 어쨌든 여기에서 원하는 것)으로 정상적으로 실행됩니다.
MaxDegreeOfParallelism
실행되는 동시 작업 수를 제어합니다. 데이터가 분할되고 처리되는 최대 분할 수를 지정하는 것과 비슷합니다. 만약TaskCreationOptions.LongRunning
이 모든 작업은 한 번에 실행되는 작업의 수를 제한하는 것과 같습니다.TaskScheduler
최대 동시성 레벨이 그 값으로 설정된 경우,이 예제와 비슷하다..
너는Parallel.ForEach
. 그러나,MaxDegreeOfParallelism
그러한 많은 수와 같으면 실제로 많은 스레드가 동시에 실행되는 것을 보장하지는 않습니다. 태스크는 여전히ThreadPoolTaskScheduler
. 그 스케줄러는 가능한 한 가장 적은 양으로 한 번에 실행되는 스레드의 수입니다. 두 방법의 가장 큰 차이점은 제가 가정 한 것입니다. 당신은 당신 자신의 것을 쓸 수 있습니다.TaskScheduler
그것은 병렬 처리의 최대 정도를 모방하고, 두 세계의 최고를 가졌지 만, 당신이하고 싶은 것에 무언가 의심하고 있습니다.
내 생각에 대기 시간과 실제 요청 횟수에 따라 작업을 사용하면 많은 (?) 경우에 더 나은 성능을 발휘하지만 더 많은 메모리를 사용하면 성능이 향상되지만 병렬 환경에서는 리소스 사용이보다 일관성있게 유지됩니다. 물론 비동기 I / O는이 두 가지 옵션 중 가장 뛰어난 성능을 발휘할 것입니다. 그러나 기존 라이브러리를 사용하고 있기 때문에 그렇게 할 수 없다는 것을 알고 있습니다. 불행히도, 당신이 선택한 어떤 사람이든 상관없이 평범한 공연에 머물러있을 것입니다.
실제 솔루션은 비동기 I / O를 수행하는 방법을 찾는 것입니다. 상황을 모르기 때문에 나는 그보다 더 도움이 될 수 있다고 생각지 않습니다. 프로그램 (읽기, 스레드)은 계속 실행되고 커널은 I / O 작업이 완료 될 때까지 기다립니다 (I / O 완료 포트 사용이라고도 함). 스레드가 대기 상태가 아니기 때문에 런타임은 적은 수의 스레드에서 더 많은 작업을 수행 할 수 있으며 보통 코어 수와 스레드 수 사이의 최적 관계로 끝납니다. 내가 원하는대로 많은 스레드를 추가하는 것이 더 나은 성능 (실제로 컨텍스트 스위칭과 같은 이유로 인해 종종 성능을 해칠 수 있음)과 동일하지 않습니다.
그러나이 전체 답변은 a를 결정할 때 쓸모가 없습니다.결정적인귀하의 질문에 대한 답변, 비록 그것이 당신에게 필요한 방향을 줄 수 있기를 바랍니다. 프로필을 작성할 때까지 어떤 성과가 더 좋은지 알 수 없습니다. 둘 다 시도하지 않으면 (나는 LongRunning 옵션이없는 태스크를 의미해야하며, 스케줄러가 스레드 전환을 처리하도록 함), 프로파일 링하여 가장 적합한 것이 무엇인지 판별하십시오특정 유스 케이스너는 너 자신을 파는거야.
두 옵션 모두 사용자 시나리오에 대해 부적절합니다.
TaskCreationOptions.LongRunning
TPL (TPL)은 CPU와 관련이없는 작업에 더 나은 선택입니다.Parallel
클래스 / 확장)은 거의 모든 코어 (스레드가 아닌)에서 실행하여 CPU 바인딩 작업의 처리량을 최대화하기위한 것입니다.
그러나 1000 개의 작업은 허용되지 않는 숫자입니다. 그들이 모두 한꺼번에 작동하는지 여부는 문제가 아닙니다. 동기 I / O를 기다리는 100 개의 스레드조차도 견딜 수없는 상황입니다. 의견에서 알 수 있듯이 응용 프로그램은 엄청난 양의 메모리를 사용하고 문맥 전환에 거의 모든 시간을 소비하게됩니다. TPL은이 규모에 맞게 설계되지 않았습니다.
귀하의 작업이 I / O 경계에 있고 웹 서비스를 사용하는 경우,그들은- 비동기 I / O는 올바른 솔루션 일뿐만 아니라만해결책. 원래 코드가없는 주요 인터페이스에 비동기 메소드를 추가하는 경우와 같이 일부 코드를 다시 설계해야하는 경우해I / O 완료 포트가만이 특정 유형의 동시성을 제대로 지원할 수있는 Windows 또는 .NET의 메커니즘.
비동기 I / O가 어떻게 든 "옵션이 아닌"상황을 들어 본 적이 없습니다. 이 제약에 대한 유효한 유스 케이스를 생각조차 할 수 없다. 비동기 I / O를 사용할 수없는 경우 수정해야하는 심각한 디자인 문제가 있음을 나타내며,최대한 빨리.
BeginXxx()
/EndXxx()
방법 대신에Xxx()
방법. 우리가 정확히 말하는 방법은 정확히 무엇을하고 있는지에 달려 있습니다.WebRequest
또는Socket
또는 어쩌면 다른 것). 그만큼Begin
/End
그런 다음 메소드는 내부적으로 I / O 완료 포트를 사용합니다. - svick
이것은 직접 비교가 아니지만 도움이 될 것 같습니다. 나는 당신이 묘사하는 것과 비슷한 것을한다. (내 경우에는 REST 호출을 제공하는 다른 쪽 끝에로드 밸런싱 서버 클러스터가있다.) 나는 좋은 결과를 얻는다.Parrallel.ForEach
최적의 작업자 스레드 수를 늘리기나는 또한 다음 코드를 사용한다.내 운영 체제에 평소보다 많은 수의 엔드 포인트에 연결할 수 있다고 알려줍니다.
var servicePointManager = System.Net.ServicePointManager.FindServicePoint(Uri);
servicePointManager.ConnectionLimit = 250;
연결하는 각 고유 URL에 대해 한 번씩 호출해야합니다.
Task
과Parallel
). 기껏해야 두 가지 중 적은 수를 선택해야합니다.묘악. - Aaronaught