IO 바인딩 작업에 ThreadPools 또는 Task Parallel Library를 사용해야합니까?
애그리 게이터 인 내 프로젝트 중 하나에서 웹에서 피드, 팟 캐스트 등을 구문 분석합니다.
순차 접근 방식을 사용하면 리소스가 많기 때문에 모든 리소스를 처리하는 데 상당한 시간이 걸립니다 (네트워크 문제 및 유사한 문제로 인해).
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이 순차적 접근 방식처럼 작동합니까 아니면 여전히 동시성을 제공합니까? 나는 이미 Microsoft .NET으로 Parallel Programming을 읽고 있으므로 책을 읽고 있지만 이에 대한 정확한 답을 찾을 수 없습니다.
참고 : 이것은 이전 질문을 다시 표현한 것입니다 [ 스레드 동시성과 병렬성을 함께 사용할 수 있습니까? ] 꽤 잘못된 표현이었습니다.
그래서 나는 대신 이것에 대한 테스트를 작성하고 실제 데이터에서 확인하기로 결정했습니다.
테스트 범례
- 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도 또 다른 실행 가능한 대안입니다.
스스로 테스트 실행
여기 에서 소스를 다운로드하고 직접 실행할 수 있습니다 . 결과를 게시 할 수 있으면 나도 추가하겠습니다.
업데이트 : 소스 링크를 수정했습니다.
If you're trying to maximize throughput for IO-bound tasks you absolutely must combine the traditional Asynchronous Processing Model (APM) APIs with your TPL based work. The APM APIs are the only way to unblock the CPU thread whilst the asynchronous IO callback is pending. The TPL provides the TaskFactory::FromAsync
helper method to assist in combining APM and TPL code.
Check out this section of the .NET SDK on MSDN entitled TPL and Traditional .NET Asynchronous Programming for more information on how to combine these two programming models to achieve async nirvana.
You are right that the TPL does remove some of the control you have when you create your own thread pool. But this is only correct if you do not want to dig deeper. The TPL does allow you to create long running Tasks that are not part of the TPL thread pool and could serve your purpose well. The published book which is a free read Parallel Programming with Microsoft .NET will give you much more insight how the TPL is meant to be used. You have always the option to give Paralle.For, Tasks explicit parameters how many threads should be allocated. Besides this you can replace the TPL scheduler with your own one if your want full control.
You can assign your own task scheduler to a TPL task. The default work stealing one is quite clever though.
I do fear of TPL producing similar results to sequential approach for my IO-bound case.
I think it will. What is the bottleneck? Is is parsing or downloading? Multithreading will not help you much with downloading from the web.
I would use Task Parallel Library for cropping, applying mask or effects for downloaded images, cuting some sample from podcast etc. It's more scalable.
But it will not be the order of magnitude speed up. Spend your resources to implementing some features, testing.
PS. "Wow my function execustes in 0.7 s instead of 0.9" ;)
If you parallelize your calls to the urls, I think it will improve your application, even if have only one core. Take a look on this code:
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
The difference between multithreading and asynchrony in this case is how the callback/completion is done.
When using EAP the number of tasks is not related with the number of threads.
As you're relying on the GetAsync task, the http client uses a networkstream (socket, tcp client or whatever) and signalize it to raise an event when the BeginRead/EndRead is done. So, no threads are involved in this moment.
After the completion is called, maybe a new thread is created, but it's up to TaskScheduler (used in call GetAsync/ContinueWith call) to create a new thread, use an existing thread or inline the task to use the calling thread.
If the AnalyzeThisWords
blocks for too much time, then you start to get bottlenecks as the "callback" on the ContinueWith is done from a thread pool worker.
'Programing' 카테고리의 다른 글
.dll 파일을 열어 내부 내용을 확인하는 방법은 무엇입니까? (0) | 2020.10.17 |
---|---|
"해당 파일 또는 디렉토리가 없습니다"이지만 존재합니다. (0) | 2020.10.17 |
포크 : 재시도 : 리소스를 일시적으로 사용할 수 없음 (0) | 2020.10.17 |
Google 스프레드 시트에서 맞춤 함수로 검색 한 데이터 새로 고침 (0) | 2020.10.17 |
문자열 벡터에 대한 조인 연산자에 해당하는 것은 무엇입니까? (0) | 2020.10.17 |