IO 바인딩 작업에 ThreadPools 또는 Task Parallel Library를 사용해야합니까?


78

애그리 게이터 인 내 프로젝트 중 하나에서 웹에서 피드, 팟 캐스트 등을 구문 분석합니다.

순차 접근 방식을 사용하는 경우 리소스가 많기 때문에 모든 리소스를 처리하는 데 상당한 시간이 걸립니다 (네트워크 문제 및 이와 유사한 문제로 인해).

foreach(feed in feeds)
{
   read_from_web(feed)
   parse(feed)
}

그래서 동시성을 구현하고 싶고 기본적으로 ThreadPools를 사용하여 작업자 스레드로 처리해야하는지 아니면 TPL에 의존하여 정렬할지 결정할 수 없었습니다.

ThreadPools는 확실히 작업자 스레드로 작업을 처리하고 내가 기대하는 바를 얻을 수 있습니다 (멀티 코어 CPU 환경에서는 다른 코어도 활용됩니다).

동시성

그래도 TPL도 추천 방법으로 고려하고 싶지만 조금 걱정이됩니다. 우선 TPL이 ThreadPools를 사용하지만 의사 결정의 추가 계층을 추가한다는 것을 알고 있습니다. 저는 주로 단일 코어 환경이 존재하는 상황에 대해 걱정합니다. 내가 틀리지 않았다면 TPL은 처음에 사용 가능한 CPU 코어 수와 동일한 작업자 스레드 수로 시작됩니다. TPL이 내 IO 바인딩 사례에 대해 순차적 접근 방식과 유사한 결과를 생성하는 것이 두렵습니다.

따라서 IO 바인딩 작업 (내 경우에는 웹에서 리소스 읽기)의 경우 ThreadPools를 사용하고 사물을 제어하는 ​​것이 가장 좋을까요, 아니면 TPL에 의존하는 것이 더 좋을까요? IO 바인딩 시나리오에서도 TPL을 사용할 수 있습니까?

업데이트 : 내 주요 관심사는 단일 코어 CPU 환경에서 TPL이 순차적 접근 방식처럼 작동합니까 아니면 여전히 동시성을 제공합니까? 나는 이미 Parallel Programming with Microsoft .NET을 읽고 있으므로 책을 읽었 지만 이에 대한 정확한 답을 찾을 수 없었습니다.

참고 : 이것은 이전 질문을 다시 표현한 것입니다 [ 스레드 동시성과 병렬성을 함께 사용할 수 있습니까? ] 꽤 잘못된 표현이었습니다.

답변:


107

그래서 나는 대신 이것에 대한 테스트를 작성하고 실제 데이터에서보기로 결정했습니다.

테스트 범례

  • Itr : 반복
  • Seq : 순차적 접근.
  • PrlEx : 병렬 확장-Parallel.ForEach
  • TPL : 작업 병렬 라이브러리
  • TPool : ThreadPool

시험 결과

싱글 코어 CPU [Win7-32]-VMWare에서 실행-

Test Environment: 1 physical cpus, 1 cores, 1 logical cpus.
Will be parsing a total of 10 feeds.
________________________________________________________________________________

Itr.    Seq.    PrlEx   TPL     TPool
________________________________________________________________________________

#1      10.82s  04.05s  02.69s  02.60s
#2      07.48s  03.18s  03.17s  02.91s
#3      07.66s  03.21s  01.90s  01.68s
#4      07.43s  01.65s  01.70s  01.76s
#5      07.81s  02.20s  01.75s  01.71s
#6      07.67s  03.25s  01.97s  01.63s
#7      08.14s  01.77s  01.72s  02.66s
#8      08.04s  03.01s  02.03s  01.75s
#9      08.80s  01.71s  01.67s  01.75s
#10     10.19s  02.23s  01.62s  01.74s
________________________________________________________________________________

Avg.    08.40s  02.63s  02.02s  02.02s
________________________________________________________________________________

싱글 코어 CPU [WinXP]-VMWare에서 실행-

Test Environment: 1 physical cpus, NotSupported cores, NotSupported logical cpus.
Will be parsing a total of 10 feeds.
________________________________________________________________________________

Itr.    Seq.    PrlEx   TPL     TPool
________________________________________________________________________________

#1      10.79s  04.05s  02.75s  02.13s
#2      07.53s  02.84s  02.08s  02.07s
#3      07.79s  03.74s  02.04s  02.07s
#4      08.28s  02.88s  02.73s  03.43s
#5      07.55s  02.59s  03.99s  03.19s
#6      07.50s  02.90s  02.83s  02.29s
#7      07.80s  04.32s  02.78s  02.67s
#8      07.65s  03.10s  02.07s  02.53s
#9      10.70s  02.61s  02.04s  02.10s
#10     08.98s  02.88s  02.09s  02.16s
________________________________________________________________________________

Avg.    08.46s  03.19s  02.54s  02.46s
________________________________________________________________________________

듀얼 코어 CPU [Win7-64]

Test Environment: 1 physical cpus, 2 cores, 2 logical cpus.
Will be parsing a total of 10 feeds.
________________________________________________________________________________

Itr.    Seq.    PrlEx   TPL     TPool
________________________________________________________________________________

#1      07.09s  02.28s  02.64s  01.79s
#2      06.04s  02.53s  01.96s  01.94s
#3      05.84s  02.18s  02.08s  02.34s
#4      06.00s  01.43s  01.69s  01.43s
#5      05.74s  01.61s  01.36s  01.49s
#6      05.92s  01.59s  01.73s  01.50s
#7      06.09s  01.44s  02.14s  02.37s
#8      06.37s  01.34s  01.46s  01.36s
#9      06.57s  01.30s  01.58s  01.67s
#10     06.06s  01.95s  02.88s  01.62s
________________________________________________________________________________

Avg.    06.17s  01.76s  01.95s  01.75s
________________________________________________________________________________

쿼드 코어 CPU [Win7-64]-HyprerThreading 지원-

Test Environment: 1 physical cpus, 4 cores, 8 logical cpus.
Will be parsing a total of 10 feeds.
________________________________________________________________________________

Itr.    Seq.    PrlEx   TPL     TPool
________________________________________________________________________________

#1      10.56s  02.03s  01.71s  01.69s
#2      07.42s  01.63s  01.71s  01.69s
#3      11.66s  01.69s  01.73s  01.61s
#4      07.52s  01.77s  01.63s  01.65s
#5      07.69s  02.32s  01.67s  01.62s
#6      07.31s  01.64s  01.53s  02.17s
#7      07.44s  02.56s  02.35s  02.31s
#8      08.36s  01.93s  01.73s  01.66s
#9      07.92s  02.15s  01.72s  01.65s
#10     07.60s  02.14s  01.68s  01.68s
________________________________________________________________________________

Avg.    08.35s  01.99s  01.75s  01.77s
________________________________________________________________________________

요약

  • 단일 코어 환경에서 실행하든 멀티 코어 환경에서 실행하든 Parallel Extensions, TPL 및 ThreadPool 은 동일하게 작동하며 대략적인 결과를 제공합니다 .
  • 여전히 TPL 에는 쉬운 예외 처리, 취소 지원 및 작업 결과를 쉽게 반환하는 기능과 같은 장점 이 있습니다 . Parallel Extensions도 또 다른 실행 가능한 대안입니다.

스스로 테스트 실행

여기 에서 소스를 다운로드하고 직접 실행할 수 있습니다 . 결과를 게시 할 수 있으면 나도 추가하겠습니다.

업데이트 : 소스 링크를 수정했습니다.


6
+1 과학적 접근 방식을 사용하여 문제를 해결합니다. 내가 착각하지 않으면 위의 모든 기술은 비슷한 결과를 설명하는 스레드 풀을 사용합니다. 일반적으로 구문이 매우 간단하고 게으 르기 때문에 병렬 확장을 사용하는 것을 좋아합니다.
Jacobs Data Solutions

나는 소스를 조금 더 청소했습니다. github.com/raistlinthewiz/concurrency-tests
HuseyinUslu

1
테스트를 위해 모든 작업을 수행해 주셔서 감사합니다.
GregoryBrad

15

IO 바인딩 작업의 처리량을 최대화하려는 경우 기존 APM (Asynchronous Processing Model) API를 TPL 기반 작업과 결합 해야합니다 . APM API는 비동기 IO 콜백이 보류중인 동안 CPU 스레드의 차단을 해제하는 유일한 방법입니다. TPL은 APM과 TPL 코드를 결합하는 데 도움이 되는 TaskFactory::FromAsync도우미 메서드 를 제공 합니다 .

이 두 프로그래밍 모델을 결합하여 비동기식 열반을 달성하는 방법에 대한 자세한 내용은 MSDN에서 TPL 및 기존 .NET 비동기 프로그래밍 이라는 제목의 .NET SDK 섹션을 확인하십시오 .


2

TPL이 자신의 스레드 풀을 만들 때 가지고있는 일부 컨트롤을 제거하는 것은 맞습니다. 그러나 이것은 더 깊이 파고 싶지 않은 경우에만 정확합니다. TPL을 사용하면 TPL 스레드 풀에 속하지 않고 목적에 잘 부합 할 수있는 장기 실행 작업을 만들 수 있습니다. 무료로 읽을 수 있는 Microsoft .NET사용한 병렬 프로그래밍 책인 출판 된 책 은 TPL이 어떻게 사용되는지 훨씬 더 많은 통찰력을 제공합니다. Paralle.For, Tasks에 할당해야하는 스레드 수를 명시 적으로 매개 변수로 지정하는 옵션이 항상 있습니다. 이 외에도 모든 권한을 원하는 경우 TPL 스케줄러를 자신의 스케줄러로 바꿀 수 있습니다.


1

TPL 작업에 자신의 작업 스케줄러 를 할당 할 수 있습니다 . 하나를 훔치는 기본 작업 은 매우 영리합니다.


나는 그 자료를 읽었고 실제로 이것 때문에 걱정된다. .NET Framework 4에서 기본 작업 스케줄러는 스레드 풀과 긴밀하게 통합됩니다. 기본 작업 스케줄러를 사용하는 경우 병렬 작업을 실행하는 작업자 스레드는 .NET ThreadPool 클래스에서 관리됩니다. 일반적으로 컴퓨터 에는 코어만큼의 작업자 스레드가 있습니다. -단일 코어 환경에서 실행중인 경우 어떻게합니까? 설명을 찾을 수 없습니다 ..
HuseyinUslu 2011 년

1
따라서 최소 수준의 병렬 처리 를 적용하고 싶 습니까? 예를 들어이 경우 마지막 X도 정도입니까? 당신이 원하는 TaskCreationOptions.LongRunning 것일 수 있습니다. 기본 스케줄러가 원하는 작업을 수행하도록 설득 할 수없는 경우 사용자 지정 스케줄러가 또 다른 옵션입니다.
ehnmark 2011 년

실제로 게시 한 테스트 결과에 따르면 내 우려는 유효하지 않습니다.
HuseyinUslu 2011 년

0

TPL이 내 IO 바인딩 사례에 대해 순차적 접근 방식과 유사한 결과를 생성하는 것이 두렵습니다.

그럴 것이라고 생각합니다. 병목 현상은 무엇입니까? 파싱 ​​또는 다운로드 중입니까? 멀티 스레딩은 웹에서 다운로드하는 데 큰 도움이되지 않습니다.

작업 병렬 라이브러리를 사용하여 자르기, 다운로드 한 이미지에 마스크 또는 효과 적용, 팟 캐스트에서 일부 샘플 자르기 등을 수행합니다. 확장 성이 더 뛰어납니다.

그러나 그것은 속도 향상 정도가 아닙니다. 일부 기능을 구현하고 테스트하는 데 리소스를 투자하십시오.

추신. "Wow my function execustes in 0.7 s instead of 0.9";)


병목 현상은 콘텐츠를 다운로드하는 것입니다. 일반 사용자가 10 개 이상의 피드를 구독하고 내 테스트에서 순차적 접근 방식으로 모든 피드를 다운로드하고 구문 분석하는 데 적어도 내 테스트 하위 집합의 경우 15 초 이상이 걸립니다. 개선의 여지가 충분하다고 생각합니다.
HuseyinUslu 2011 년

내가 게시 한 테스트 결과에 따르면 개선의 여지가 충분하다는 것이 사실 인 것 같습니다.
HuseyinUslu 2011 년

0

URL에 대한 호출을 병렬화하면 코어가 하나만 있어도 애플리케이션이 향상 될 것이라고 생각합니다. 이 코드를 살펴보십시오.

var client = new HttpClient();
var urls = new[]{"a", "url", "to", "find"};

// due to the EAP pattern, this will run in parallel.
var tasks = urls.Select(c=> client.GetAsync(c));

var result = Tasks.WhenAll(task).ContinueWith(a=> AnalyzeThisWords(a.Result));
result.Wait(); // don't know if this is needed or it's correct to call wait

이 경우 멀티 스레딩과 비 동시성의 차이점은 콜백 / 완료가 수행되는 방식입니다.

EAP를 사용할 때 작업 수는 스레드 수와 관련이 없습니다.

GetAsync 작업에 의존하고 있으므로 http 클라이언트는 네트워크 스트림 (소켓, tcp 클라이언트 등)을 사용하고 BeginRead / EndRead가 완료되면 이벤트를 발생 시키도록 신호를 보냅니다. 따라서이 순간에는 스레드가 없습니다.

완료가 호출 된 후 새 스레드가 생성 될 수 있지만 새 스레드를 생성하거나 기존 스레드를 사용하거나 작업을 인라인하여 호출 스레드를 사용하는 것은 TaskScheduler (GetAsync / ContinueWith 호출 호출에 사용됨)에 달려 있습니다.

경우 AnalyzeThisWords너무 많은 시간 블록, 당신은 스레드 풀 노동자에서 수행하는 ContinueWith에서 "콜백"로 병목 현상을 얻을 시작합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.