답변:
지속적인 처리가 필요한 논리적 인 작업이 많고 동시에 수행하려면 pool + scheduler를 사용하십시오.
원격 서버 또는 디스크 액세스에서 자료 다운로드와 같은 IO 관련 작업을 동시에 수행해야하지만 몇 분마다 한 번씩 말해야하는 경우, 고유 한 스레드를 작성하고 완료되면 종료하십시오.
편집 : 몇 가지 고려 사항에 대해 데이터베이스 액세스, 물리 / 시뮬레이션, AI (게임) 및 많은 사용자 정의 작업을 처리하는 가상 시스템에서 실행되는 스크립트 작업에 스레드 풀을 사용합니다.
일반적으로 풀은 프로세서 당 2 개의 스레드 (현재 요즘 4 개)로 구성되지만 필요한 수를 알고있는 경우 원하는 스레드 수를 설정할 수 있습니다.
편집 : 자신의 스레드를 만드는 이유는 컨텍스트 변경 때문입니다 (스레드가 메모리와 함께 프로세스 안팎으로 스왑 해야하는 경우). 쓰레드를 사용하지 않을 때와 같이 쓸모없는 컨텍스트 변경이 발생하면 예를 들어 마치 그대로두면 프로그램 성능이 쉽게 절반으로 떨어질 수 있습니다 (예 : 3 개의 휴면 스레드와 2 개의 활성 스레드가 있음). 따라서 다운로드 스레드가 대기 중이면 많은 CPU를 소비하고 실제 응용 프로그램의 캐시를 냉각시킵니다.
.Net의 스레드 풀에 대한 요약은 다음과 같습니다. http://blogs.msdn.com/pedram/archive/2007/08/05/dedicated-thread-or-a-threadpool-thread.aspx
게시물에는 스레드 풀을 사용하지 말고 자체 스레드를 대신 시작해야 할 때도 있습니다.
이 무료 전자 책을 읽는 것이 좋습니다. Josephing by Threading in C #
최소한 "시작하기"섹션을 읽으십시오. 전자 책은 훌륭한 소개를 제공하며 풍부한 고급 스레딩 정보도 포함합니다.
스레드 풀 사용 여부를 아는 것은 시작에 불과합니다. 다음으로 요구에 가장 적합한 스레드 풀을 입력하는 방법을 결정해야합니다.
이 전자 책은이 모든 것을 설명하고 그것들을 언제 사용할 것인지 조언하고 나만의 스레드를 만듭니다.
스레드 풀은 스레드 간의 컨텍스트 전환을 줄 이도록 설계되었습니다. 여러 구성 요소가 실행중인 프로세스를 고려하십시오. 이러한 각 구성 요소는 작업자 스레드를 생성 할 수 있습니다. 프로세스에서 스레드가 많을수록 컨텍스트 전환에 더 많은 시간이 낭비됩니다.
이제 각 구성 요소가 스레드 풀에 항목을 큐에 넣는 경우 컨텍스트 전환 오버 헤드가 훨씬 줄어 듭니다.
스레드 풀은 CPU (또는 CPU 코어)에서 수행되는 작업을 최대화하도록 설계되었습니다. 이것이 기본적으로 스레드 풀이 프로세서 당 여러 스레드를 스핀 업하는 이유입니다.
스레드 풀을 사용하지 않으려는 상황이 있습니다. I / O를 기다리거나 이벤트를 기다리는 경우 해당 스레드 풀 스레드를 묶어 다른 사람이 사용할 수 없습니다. 장기 실행 작업을 구성하는 것이 주관적이지만 동일한 아이디어가 장기 실행 작업에 적용됩니다.
Pax Diablo도 좋은 지적입니다. 실을 회전시키는 것은 자유롭지 않습니다. 시간이 걸리고 스택 공간을 위해 추가 메모리를 소비합니다. 스레드 풀은 스레드를 재사용하여이 비용을 상각합니다.
참고 : 스레드 풀 스레드를 사용하여 데이터를 다운로드하거나 디스크 I / O를 수행하는 방법에 대해 질문했습니다. 이를 위해 스레드 풀 스레드를 사용해서는 안됩니다 (위에 설명한 이유로). 대신 비동기 I / O (일명 BeginXX 및 EndXX 메소드)를 사용하십시오. A의 FileStream
그 것 BeginRead
하고 EndRead
. 들어 HttpWebRequest
있을 것이라고 BeginGetResponse
하고 EndGetResponse
. 사용하기가 더 복잡하지만 멀티 스레드 I / O를 수행하는 올바른 방법입니다.
스레드 기아가 발생하기 쉬우므로 처리 과정에서 중요하거나 가변적이거나 알려지지 않은 부분을 차단할 수있는 작업에 대해서는 .NET 스레드 풀에주의하십시오. 스레드 작업에 대해 많은 논리적 추상화를 제공하는 .NET 병렬 확장 사용을 고려하십시오. ThreadPool에서 개선되어야 할 새로운 스케줄러도 포함되어 있습니다. 여기를 참조 하십시오
응용 프로그램의 전체 수명과 같이 오랜 시간 동안 지속되는 백그라운드 작업이있는 경우 자체 스레드를 만드는 것이 합리적입니다. 스레드에서 수행해야하는 짧은 작업이있는 경우 스레드 풀링을 사용하십시오.
많은 스레드를 작성하는 응용 프로그램에서는 스레드 작성의 오버 헤드가 상당히 커집니다. 스레드 풀을 사용하면 스레드가 한 번 작성되어 재사용되므로 스레드 작성 오버 헤드가 발생하지 않습니다.
내가 작업 한 응용 프로그램에서 스레드를 만드는 것에서 짧은 수명의 스레드에 대한 스레드 풀을 사용하는 것으로 변경하면 실제로 응용 프로그램을 통과시키는 데 도움이되었습니다.
동시 실행 단위로 최고의 성능을 얻으려면 시작시 스레드 객체 풀이 생성되고 차단 (이전 일시 중단)으로 이동하여 컨텍스트 실행 대기 (표준 인터페이스가 구현 된 객체) 인 자체 스레드 풀을 작성하십시오. 귀하의 코드).
Tasks vs. Threads vs. .NET ThreadPool에 대한 많은 기사가 실제로 성능 결정에 필요한 것을 제시하지 못했습니다. 그러나 그것들을 비교하면 스레드가 승리하고 특히 스레드 풀이 나옵니다. CPU 전체에 가장 잘 분산되어 더 빨리 시작됩니다.
논의해야 할 것은 Windows의 주요 실행 단위 (Windows 10 포함)가 스레드이며 OS 컨텍스트 전환 오버 헤드가 무시할 수 있다는 사실입니다. 간단히 말해서, 기사가 컨텍스트 전환을 저장하여 더 높은 성능을 요구하는지 또는 더 나은 CPU 사용을 요구하는지에 관계없이 이러한 기사 중 많은 기사에 대한 확실한 증거를 찾지 못했습니다.
이제 약간의 사실감이 있습니다.
우리 대부분은 응용 프로그램이 결정론적일 필요가 없으며, 대부분 운영 체제 개발과 함께 제공되는 스레드에 대한 노크 배경이 없습니다. 위에서 쓴 것은 초보자를위한 것이 아닙니다.
가장 중요한 것은 토론하기가 프로그래밍하기 쉬운 것입니다.
자체 스레드 풀을 만들면 실행 상태 추적, 일시 중단 및 다시 시작을 시뮬레이션하는 방법 및 응용 프로그램 전체를 포함하여 실행을 취소하는 방법과 관련하여 작성해야 할 내용이 약간 있습니다. 닥쳐. 또한 풀을 동적으로 확장 할 것인지와 풀의 용량 제한에 대해 염려해야 할 수도 있습니다. 한 시간 안에 이러한 프레임 워크를 작성할 수 있지만 여러 번 수행했기 때문입니다.
실행 단위를 작성하는 가장 쉬운 방법은 작업을 사용하는 것입니다. 작업의 장점은 하나의 코드를 작성하여 코드에서 인라인으로 시작할 수 있다는 것입니다 (주의해야 할 수도 있음). 작업을 취소 할 때 처리 할 취소 토큰을 전달할 수 있습니다. 또한 체인 이벤트에 약속 방식을 사용하며 특정 유형의 값을 반환하도록 할 수 있습니다. 또한 async 및 await를 사용하면 더 많은 옵션이 존재하며 코드가 더 이식성이 뛰어납니다.
본질적으로 Tasks vs. Threads vs. .NET ThreadPool의 장단점을 이해하는 것이 중요합니다. 고성능이 필요한 경우 스레드를 사용하고 자체 풀을 사용하는 것을 선호합니다.
쉽게 비교할 수있는 방법은 512 스레드, 512 작업 및 512 ThreadPool 스레드를 시작하는 것입니다. Threads (왜 스레드 스레드를 작성해야하는지)로 시작하면 지연이 발생하지만 Tasks 및 .NET ThreadPool 스레드는 모두 시작하는 데 몇 분이 걸리지 만 몇 초 안에 512 개의 모든 스레드가 실행됩니다.
다음은 이러한 테스트 결과 (16GB RAM이 장착 된 i5 쿼드 코어)로 30 초마다 실행됩니다. 실행 된 코드는 SSD 드라이브에서 간단한 파일 I / O를 수행합니다.
스레드 풀은 사용 가능한 스레드보다 처리 할 작업이 많을 때 유용합니다.
모든 작업을 스레드 풀에 추가하고 특정 시간에 실행할 수있는 최대 스레드 수를 지정할 수 있습니다.
MSDN 에서이 페이지를 확인하십시오 . http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80).aspx
나는 보통 다른 스레드에서 무언가를 할 필요가있을 때마다 Threadpool을 사용하며 실제로 실행되거나 종료 될 때 신경 쓰지 않습니다. 로깅이나 파일 다운로드와 같은 것 (비동기 스타일을 수행하는 더 좋은 방법이 있지만). 더 많은 제어가 필요할 때 내 스레드를 사용합니다. 또한 내가 찾은 것은 스레드 안전 대기열 (자신의 해킹)을 사용하여 "명령 객체"를 저장하는 것이> 1 스레드에서 작업 해야하는 여러 명령이있을 때 좋습니다. 따라서 Xml 파일을 분할하여 각 요소를 대기열에 넣은 다음 여러 요소를 처리하여 여러 요소를 처리 할 수 있습니다. 나는 C #으로 변환 한 uni (VB.net!)로 돌아가는 대기열 방법을 썼습니다. 특별한 이유없이 아래에 포함 시켰습니다 (이 코드에는 약간의 오류가있을 수 있습니다).
using System.Collections.Generic;
using System.Threading;
namespace ThreadSafeQueue {
public class ThreadSafeQueue<T> {
private Queue<T> _queue;
public ThreadSafeQueue() {
_queue = new Queue<T>();
}
public void EnqueueSafe(T item) {
lock ( this ) {
_queue.Enqueue(item);
if ( _queue.Count >= 1 )
Monitor.Pulse(this);
}
}
public T DequeueSafe() {
lock ( this ) {
while ( _queue.Count <= 0 )
Monitor.Wait(this);
return this.DeEnqueueUnblock();
}
}
private T DeEnqueueUnblock() {
return _queue.Dequeue();
}
}
}
가능한 한 짧은 대기 시간으로 코어 전체에 작업을 분산시키는 스레드 풀을 원했으며 다른 응용 프로그램과 잘 어울리지 않아도되었습니다. .NET 스레드 풀 성능이 좋지 않은 것으로 나타났습니다. 코어 당 하나의 스레드를 원한다는 것을 알고 있으므로 자체 스레드 풀 대체 클래스를 작성했습니다. 이 코드는 여기 다른 StackOverflow 질문에 대한 답변으로 제공됩니다 .
원래 질문에 관해서, 스레드 풀은 반복 계산을 병렬로 실행할 수있는 부분으로 나눌 때 유용합니다 (결과를 변경하지 않고 병렬로 실행할 수 있다고 가정). 수동 스레드 관리는 UI 및 IO와 같은 작업에 유용합니다.