문제

저는 C#에서 다중 스레드 프로그래밍을 배우려고 노력해 왔으며 언제 스레드 풀을 사용하는 것이 가장 좋은지 혼란스럽습니다.내 자신의 스레드를 만듭니다.한 책에서는 작은 작업에만 스레드 풀을 사용할 것을 권장하지만(그게 무엇을 의미하든) 실제 지침을 찾을 수 없는 것 같습니다.프로그래밍 결정을 내릴 때 어떤 점을 고려하시나요?

도움이 되었습니까?

해결책

일정한 처리가 필요한 논리적 작업이 많고 병렬로 수행하려는 경우 Pool+Scheduler를 사용하십시오.

원격 서버 또는 디스크 액세스에서 물건을 다운로드하는 것과 같이 IO 관련 작업을 동시에 동시에 만들어야하지만 몇 분마다 한 번씩이 말을해야한다면 나만의 스레드를 만들고 완료되면 죽입니다.

편집 : 일부 고려 사항에 대해서는 데이터베이스 액세스, 물리/시뮬레이션, AI (게임)에 스레드 풀을 사용하고 스크립트 작업에는 많은 사용자 정의 작업을 처리하는 가상 머신에서 실행되었습니다.

일반적으로 풀은 프로세서 당 2 개의 스레드로 구성되지만 (요즘 4 개) 필요한 수를 알고 있다면 원하는 스레드의 양을 설정할 수 있습니다.

편집 : 자신의 스레드를 만드는 이유는 컨텍스트가 바뀌기 때문입니다 (스레드가 메모리와 함께 프로세스 안팎으로 교환해야 할 때). 쓸모없는 맥락이 변경되면, 스레드를 사용하지 않을 때는 말하는 것처럼 스레드를 사용하지 않으면 프로그램의 성능을 쉽게 절반으로 만들 수 있습니다 (예 : 3 개의 수면 스레드와 2 개의 활성 스레드가 있습니다). 따라서 다운로드 스레드가 기다리고 있다면 많은 CPU를 먹고 실제 애플리케이션의 캐시를 냉각시킵니다.

다른 팁

다른 언어와 같은 이유로 C#의 스레드 풀을 사용하는 것이 좋습니다.

실행중인 스레드 수를 제한하거나 스레드를 생성하고 파괴하는 오버 헤드를 원하지 않으려면 스레드 풀을 사용하십시오.

작은 작업으로, 당신이 읽은 책은 짧은 수명이있는 과제를 의미합니다. 1 초 동안 실행되는 스레드를 만드는 데 10 초가 걸리면 수영장을 사용해야하는 곳입니다 (실제 수치를 무시하면 계산되는 비율입니다).

그렇지 않으면 당신은 단순히 그들이하고자하는 일을하는 것이 아니라 실을 만들고 파괴하는 데 많은 시간을 소비합니다.

.NET의 스레드 풀에 대한 좋은 요약은 다음과 같습니다. http://blogs.msdn.com/pedram/archive/2007/08/05/dedicated-thread-or-a-a-threadpool-thread.aspx

게시물에는 스레드 풀을 사용하지 말고 대신 자신의 스레드를 시작 해야하는 시점도 있습니다.

이 무료 전자 책을 읽는 것이 좋습니다.Joseph Albahari의 C# 실링

적어도 "시작"섹션을 읽으십시오. 전자 책은 훌륭한 소개를 제공하며 풍부한 고급 스레딩 정보도 포함합니다.

스레드 풀 사용 여부를 아는 것은 시작일뿐입니다. 다음으로 스레드 풀에 들어가는 방법을 결정해야합니다. 귀하의 요구에 가장 적합합니다.

  • 작업 병렬 라이브러리 (.NET Framework 4.0)
  • ThreadPool.queueUserWorkItem
  • 비동기 대표
  • 배경 노동자

이 전자 책은이 모든 것을 설명하고 사용시기와시기와 나만의 스레드를 만듭니다.

스레드 풀은 스레드 간의 컨텍스트 전환을 줄이도록 설계되었습니다.여러 구성 요소가 실행되는 프로세스를 생각해 보세요.각 구성 요소는 작업자 스레드를 생성할 수 있습니다.프로세스에 스레드가 많을수록 컨텍스트 전환에 더 많은 시간이 낭비됩니다.

이제 각 구성 요소가 항목을 스레드 풀에 대기시키는 경우 컨텍스트 전환 오버헤드가 훨씬 줄어듭니다.

스레드 풀은 CPU(또는 CPU 코어) 전체에서 수행되는 작업을 최대화하도록 설계되었습니다.이것이 기본적으로 스레드 풀이 프로세서당 여러 스레드를 스핀업하는 이유입니다.

스레드 풀을 사용하고 싶지 않은 상황이 있습니다.I/O를 기다리고 있거나 이벤트를 기다리는 중이라면 해당 스레드 풀 스레드를 묶어서 다른 사람이 사용할 수 없게 됩니다.장기 실행 작업에도 동일한 아이디어가 적용되지만 장기 실행 작업을 구성하는 요소는 주관적입니다.

Pax Diablo도 좋은 지적을 합니다.스레드를 회전시키는 것은 무료가 아닙니다.시간이 걸리며 스택 공간을 위해 추가 메모리를 소비합니다.스레드 풀은 스레드를 재사용하여 이 비용을 상각합니다.

메모:스레드 풀 스레드를 사용하여 데이터를 다운로드하거나 디스크 I/O를 수행하는 방법에 대해 문의하셨습니다.이를 위해 스레드 풀 스레드를 사용하면 안 됩니다(위에 설명된 이유 때문에).대신 비동기 I/O(BeginXX 및 EndXX 메서드라고도 함)를 사용하세요.에 대한 FileStream 그럴 것이다 BeginRead 그리고 EndRead.대한 HttpWebRequest 그럴 것이다 BeginGetResponse 그리고 EndGetResponse.사용하기가 더 복잡하지만 다중 스레드 I/O를 수행하는 데 적합한 방법입니다.

스레드 기아가 발생하기 쉽기 때문에 처리의 중요하고 가변적이거나 알려지지 않은 부분을 차단할 수있는 작업용 .NET 스레드 풀을 조심하십시오. 스레드 작업에 대한 많은 논리적 추상화를 제공하는 .NET 병렬 확장을 고려하십시오. 또한 새로운 스케줄러가 포함되어 있으며 Threadpool에서 개선해야합니다. 보다 여기

작은 작업에만 스레드 풀을 사용하는 한 가지 이유는 제한된 수의 스레드 풀 스레드가 있기 때문입니다. 하나가 오랫동안 사용되면 해당 스레드가 다른 코드에서 사용되는 것을 막습니다. 이런 일이 여러 번 발생하면 스레드 풀이 사용될 수 있습니다.

스레드 풀을 사용하면 미묘한 효과가 발생할 수 있습니다. 일부 .NET 타이머는 스레드 풀 스레드를 사용하고 발사되지 않습니다.

응용 프로그램의 전체 수명과 같이 오랫동안 살아갈 배경 작업이있는 경우 자신만의 스레드를 만드는 것이 합리적입니다. 스레드에서 수행 해야하는 짧은 작업이있는 경우 스레드 풀링을 사용하십시오.

많은 스레드를 생성하는 응용 프로그램에서 스레드 생성의 오버 헤드가 실질적으로됩니다. 스레드 풀을 사용하면 스레드를 한 번 생성하고 재사용하여 스레드 생성 오버 헤드를 피합니다.

내가 작업 한 응용 프로그램에서, 스레드 생성에서 짧은 살아있는 스레드에 스레드 풀 사용으로 변경하면 실제로 응용 프로그램의 풋 팅에 도움이되었습니다.

동시에 실행되는 유닛을 사용하여 최고 성능을 보려면 시동시 실 오브젝트 풀이 생성되고 차단 (이전에 현탁 된)으로 이동하여 컨텍스트를 대기하여 실행을 대기합니다 (표준 인터페이스가있는 객체가 구현 된 표준 인터페이스가있는 객체 코드).

작업 대 스레드 대 .NET ThreadPool에 대한 많은 기사가 실제로 성능 결정을 내리는 데 필요한 것을 실제로 제공하지 못합니다. 그러나 비교할 때 실이 이기고 특히 실 풀이 이어집니다. 그들은 CPU에 최고로 분포되어 있으며 더 빨리 시작합니다.

논의해야 할 것은 Windows 10 포함 Windows의 기본 실행 장치가 스레드이며 OS 컨텍스트 오버 헤드는 일반적으로 무시할 수 있다는 사실입니다. 간단히 말해서, 나는이 기사가 컨텍스트 전환 또는 더 나은 CPU 사용을 저장함으로써 더 높은 성능을 주장하는지 여부에 관계없이 이러한 기사들의 설득력있는 증거를 찾을 수 없었습니다.

이제 약간의 현실주의를 위해 :

우리 대부분은 우리의 응용 프로그램이 결정 론적이어야 할 필요가 없으며, 대부분의 사람들은 스레드가있는 딱딱한 노크 배경을 가지고 있지 않으며, 예를 들어 종종 운영 체제 개발과 함께 제공됩니다. 내가 위에서 쓴 것은 초보자를위한 것이 아닙니다.

따라서 논의하는 것이 가장 중요한 것은 프로그래밍하기 쉬운 것입니다.

나만의 스레드 풀을 만드는 경우 실행 상태 추적 상태, 일시 중지 및 재개 시뮬레이션 방법 및 응용 프로그램 전체를 포함하여 실행을 취소하는 방법에 대해 약간의 글쓰기가 필요합니다. 종료. 수영장을 역동적으로 재배하고 싶은지 여부와 수영장의 용량 제한 사항에 대해서도 걱정해야 할 수도 있습니다. 나는 한 시간 안에 그런 프레임 워크를 쓸 수 있지만 그것은 내가 그것을 여러 번 해냈 기 때문입니다.

아마도 실행 장치를 작성하는 가장 쉬운 방법은 작업을 사용하는 것입니다. 작업의 아름다움은 작업을 만들어 코드에서 인라인으로 시작할 수 있다는 것입니다 (주의 할 수는 있지만). 작업을 취소하려는 경우 취급 할 취소 토큰을 전달할 수 있습니다. 또한 체인 이벤트에 대한 약속 접근법을 사용하며 특정 유형의 값을 반환 할 수 있습니다. 또한 비동기 및 기다리면 더 많은 옵션이 존재하고 코드가 더 휴대 할 수 있습니다.

본질적으로, 작업 대 스레드 대 .NET ThreadPool의 장단점을 이해하는 것이 중요합니다. 고성능이 필요한 경우 스레드를 사용하고 내 수영장을 사용하는 것을 선호합니다.

쉽게 비교하는 방법은 512 개의 스레드, 512 개의 작업 및 512 개의 스레드 풀 스레드를 시작하는 것입니다. 스레드 (따라서 스레드 풀을 작성하는 이유)로 처음에는 지연이 있지만, 512 개의 스레드는 모두 몇 초 안에 실행되는 동안 작업과 .NET 스레드 풀 스레드는 모든 시작까지 몇 분이 걸립니다.

다음은 이러한 테스트 결과 (16GB의 RAM이있는 i5 쿼드 코어)의 결과이며 각 30 초를 실행합니다. 실행 된 코드는 SSD 드라이브에서 간단한 파일 I/O를 수행합니다.

시험 결과

스레드 풀은 사용 가능한 스레드보다 처리 할 작업이 더 많을 때 좋습니다.

모든 작업을 스레드 풀에 추가하고 특정 시간에 실행할 수있는 최대 스레드 수를 지정할 수 있습니다.

체크 아웃 이것 MSDN의 페이지 :http://msdn.microsoft.com/en-us/library/3dasc8as(vs.80).aspx

가능한 경우 항상 스레드 풀을 사용하고 가능한 최고 수준의 추상화에서 작업하십시오. 스레드 풀은 당신을 위해 실을 생성하고 파괴하는 것을 숨 깁니다. 이것은 일반적으로 좋은 것입니다!

대부분의 경우 스레드를 생성하는 고가의 과정을 피할 때 수영장을 사용할 수 있습니다.

그러나 일부 시나리오에서는 스레드를 만들 수 있습니다. 예를 들어 스레드 풀을 사용하는 유일한 사람이 아닌 경우 공유 리소스를 소비하지 않기 위해 생성 된 스레드가 오래 지속되거나 스레드의 스택 크기를 제어하려는 경우.

배경 작업자를 조사하는 것을 잊지 마십시오.

나는 많은 상황에서 무거운 리프팅없이 원하는 것을 제공합니다.

건배.

나는 보통 다른 스레드에서 무언가를해야 할 때마다 ThreadPool을 사용하고 실행되거나 끝날 때 실제로 신경 쓰지 않습니다. 로깅 또는 파일을 다운로드하는 배경과 같은 것 (비동기 스타일을 수행하는 더 좋은 방법이 있지만). 더 많은 컨트롤이 필요할 때 내 스레드를 사용합니다. 또한 내가 찾은 것은 ThreadSafe 큐 (Hack Your Own)를 사용하여 "명령 개체"를 저장하는 것이 좋습니다. 따라서 XML 파일을 분할하고 각 요소를 큐에 넣은 다음이 요소에서 일부 처리를 수행하는 여러 스레드가 작동 할 수 있습니다. 나는 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와 같은 작업에 유용합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top