최신 구조 중 하나 대신 일반 오래된 Thread 객체를 사용하는 것이 더 바람직한 경우가 있습니까?


112

나는 블로그 게시물과 여기에서 많은 사람들 Thread이 C #의 최신 버전 에서 클래스 사용을 피하거나 반대하는 것을 봅니다 (물론 Task& 친구 가 추가 된 4.0 이상을 의미합니다 ). 이전에도 평범한 오래된 스레드의 기능이 많은 경우 ThreadPool클래스에 의해 대체 될 수 있다는 사실에 대한 논쟁이있었습니다 .

또한, ugly + combo를 대체하는 반면 , 우리가 가지고있는 GUI의 경우 등 다른 특수 메커니즘이 Thread클래스를 덜 매력적으로 렌더링합니다 .TimerThreadSleepBackgroundWorker

그럼에도 불구하고 Thread일부 사람들 (나 자신을 포함하여)에게는 매우 친숙한 개념으로 남아있는 것 같습니다. 어떤 종류의 병렬 실행을 포함하는 작업에 직면했을 때 바로 좋은 오래된 Thread클래스 를 사용하는 사람들 입니다. 최근에 내 방식을 수정할 때가되었는지 궁금합니다.

그래서 제 질문은 Thread위의 구조 중 하나 대신 평범한 오래된 객체 를 사용하는 것이 필요하거나 유용한 경우가 있습니까?


4
nitpick은 아니지만 (또는 어쩌면 ... :)) .NET입니다 (즉, C #에 국한되지 않음).
MetalMikester 2012 년

11
지금까지이 질문에 답한 사용자의 평균 담당자는 64.5k입니다. 꽤 인상적인 상영
zzzzBov

1
@zzzzBov : 내 자신의 답변을 게시하려고 생각하고 있었지만 지금은 평균을 낮추는 것을 두려워 할 수 없습니다. :)
Brian Gideon

@BrianGideon, 나는 그것이 당신이나 다른 사람 이이 질문에 대답하는 것을 막아야 할 이유가 없습니다.
zzzzBov

@Brian Gideon : 꼭 게시 해주세요. :)
Tudor

답변:


107

Thread 클래스는 분명히 언급 한 다른 모든 패턴 의 구현 세부 사항 이기 때문에 쓸모 없게 만들 수 없습니다 .

그러나 그것은 당신의 질문이 아닙니다. 당신의 질문은

위의 구조 중 하나 대신 일반 오래된 Thread 객체를 사용하는 것이 필요하거나 유용한 경우가 있습니까?

확실한. 높은 수준의 구성 중 하나가 사용자의 요구를 충족하지 못하는 경우입니다.

내 조언은 기존의 고추 상 도구가 사용자의 요구를 충족하지 못하는 상황에 처해 있고 스레드를 사용하여 솔루션을 구현하려는 경우 실제로 필요한 누락 된 추상화를 식별 한 다음 해당 추상화구현해야한다는 것입니다. 스레드사용하고 추상화사용합니다 .


33
모든 좋은 조언. 그러나 새로운 구조 중 하나보다 평범한 오래된 스레드 객체가 더 나은 예가 있습니까?
Robert Harvey

타이밍 문제가있는 여러 스레드를 디버깅하여 일부 코드를로드하는 것은 다른 '상위'수준 구조를 사용하는 것보다 훨씬 쉽게 수행 할 수 있습니다. 어쨌든 스레드 작업 및 사용에 대한 기본 지식이 필요합니다.
CodingBarfield

대답 해줘서 고마워, 에릭. 새로운 스레딩 기능에 대한 최근의 폭격으로 인해 때때로 이전 스레드가 여전히 필요하다는 사실을 잊기 쉽습니다. 음, 어쨌든 베어 메탈에 대한 지식이 있으면 유용하다고 생각합니다.
튜더

15
@RobertHarvey : 물론입니다. 예를 들어, 고전적인 "생산자 / 소비자"상황이있는 경우 작업 대기열에서 물건을 꺼내는 전용 스레드와 작업 대기열에 물건을 넣는 전용 스레드를 사용하려는 경우입니다. 둘 다 영원히 루프; 한동안 수행 한 작업에 잘 매핑되지 않고 결과를 얻습니다. 스레드가 두 개뿐이므로 스레드 풀이 필요하지 않습니다. 또한 잠금 및 신호를 사용하여 오랫동안 다른 스레드를 차단하지 않고 대기열을 안전하게 유지할 수 있습니다.
Eric Lippert 2012 년

@Eric : TPL Dataflow에서 이미 이러한 추상화를 제공하지 않습니까?
Allon Guralnek 2012

52

스레드는 특정 항목 (즉, 병렬성과 비 동시성)에 대한 기본 구성 요소이므로 제거해서는 안됩니다. 그러나 , 대한 대부분의 사람과 가장 (한 번에 2,000 스레드를 산란하여 시스템 과부하없이 동시에 여러 작은 작업을 처리하는 좋은 방법을 제공) 등 스레드 풀과 같은 당신이 언급 사용하는 것이 더 적절한 일이, 거기에 사용 사례, BackgroundWorker( 단일 작업에 대한 유용한 이벤트를 캡슐화합니다.)

그러나 많은 경우 프로그래머가 불필요하게 바퀴를 재발 명하고 어리석은 실수를 저지르는 등의 일을하지 않도록 보호하기 때문에 더 적절하다고해서 Thread 클래스가 쓸모가 없다는 의미는 아닙니다. 위에서 명명 된 추상화에서 여전히 사용되며 더 특별한 클래스에서 다루지 않는 스레드에 대한 세밀한 제어가 필요한 경우 여전히 필요합니다.

비슷한 맥락에서, 사람들이 어레이를 사용하는 많은 경우에 더 적합 .NET함에도 불구하고 어레이 사용을 금지하지 않습니다 List<T>. 단순히 표준 lib에서 다루지 않는 것을 빌드하고 싶을 수 있기 때문입니다.


6
자동 변속기가 99 %의 시간 동안 작동한다고해서 운전자 선호도를 무시하더라도 수동 변속기에 가치가 없다는 의미는 아닙니다.
Guvante 2012 년

4
내가 사이클리스트이자 대중 교통 사용자라는 점을 감안할 때 운전 관용구에 익숙하지 않습니다. 그러나 수동 변속기는 자동 변속기의 핵심이 아닙니다. 스틱을 움직이는 기계적인 손이 아닙니다. 내가 볼 수있는 한 그것은 다른 것에 대한 추상화가 아닙니다.
Joey

2
두 번째 단락에서 "스레드"라는 단어를 "관리되지 않는 코드"로 바꿀 수 있으며 여전히 참으로 울립니다
Conrad Frix

1
@Joey : 오, 나는 당신이 비록 대부분이 그것을 필요로하지 않더라도 유용성을 희생시키면서 세밀한 통제를 갖는 가치 인 노후화 조각을 의미한다고 생각했습니다. 기술적으로 수동 변속기의 흥미로운 부분은 어쨌든 클러치입니다.
Guvante 2012 년

3
여러분이 정말로 변속기 은유를 가지고 가고 싶다면, 대부분의 순차 변속기 (예 : BMW의 SMG 변속기) 실제로 컴퓨터 작동 클러치 및 기어 선택기가있는 수동 변속기입니다. 그들은 기존의 자동 장치와 같은 유성 기어 시스템이 아닙니다.
Adam Robinson

13

Task그리고 Thread다른 추상화입니다. 스레드를 모델링하려는 경우 Thread클래스가 여전히 가장 적절한 선택입니다. 예를 들어 현재 스레드와 상호 작용해야하는 경우 더 나은 유형이 표시되지 않습니다.

그러나 지적했듯이 .NET은 Thread많은 경우에 선호되는 몇 가지 전용 추상화를 추가했습니다 .


9

Thread클래스는 더 이상 사용되지 않으며 특별한 상황에서 여전히 유용합니다.

내가 일하는 곳에서 우리는 콘텐츠 관리 시스템의 일부로 '백그라운드 프로세서'를 작성했습니다. 즉, 디렉터리, 전자 메일 주소 및 RSS 피드를 모니터링하는 Windows 서비스, 새로운 것이 나타날 때마다 작업을 실행합니다. 일반적으로 데이터.

이를 위해 스레드 풀을 사용하려는 시도는 작동하지 않았습니다. 동시에 너무 많은 항목을 실행하고 디스크를 폐기하려고하므로 Thread클래스 를 직접 사용하여 자체 폴링 및 실행 시스템을 구현했습니다 .


여기서 Thread를 직접 사용하는 것이 올바른 해결책인지는 모르겠지만 실제로 Thread로 이동해야하는 예제를 제공하는 경우 +1입니다.
Oddthinking 2012 년

6

새로운 옵션을 사용하면 (비싼) 스레드를 직접 사용하고 관리하는 빈도를 줄일 수 있습니다.

일종의 병렬 실행과 관련된 작업에 직면했을 때 좋은 오래된 Thread 클래스를 사용하는 것으로 바로 이동하는 사람들.

이것은 작업을 병렬로 수행하는 매우 비싸고 비교적 복잡한 방법입니다.

비용이 가장 중요하다는 점에 유의하십시오. 전체 스레드를 사용하여 작은 작업을 수행 할 수는 없으며 비생산적입니다. ThreadPool은 비용을, Task 클래스는 복잡성 (예외, 대기 및 취소)을 처리합니다.


5

" 평범한 오래된 Thread 객체를 사용하는 것이 필요하거나 유용한 경우가 있습니까? "라는 질문에 답하기 위해 , 여러분이 원할 장기 실행 프로세스를 가질 때 평범한 오래된 Thread가 유용하다고 말하고 싶습니다. 다른 스레드와 상호 작용하지 마십시오.

예를 들어, 어떤 종류의 메시지 대기열에서 메시지를 수신하도록 구독하는 응용 프로그램을 작성하고 응용 프로그램이 해당 메시지를 처리하는 것 이상을 수행 할 경우 스레드를 사용하는 것이 유용 할 것입니다. 자체 포함 (즉, 완료되기를 기다리지 않음) 및 수명이 짧지 않습니다. ThreadPool 클래스를 사용하면 수명이 짧은 작업 항목을 대기열에 추가하고 ThreadPool 클래스가 새 스레드를 사용할 수있을 때 각 항목을 효율적으로 처리 할 수 ​​있습니다. 작업은 Thread를 직접 사용하는 곳에서 사용할 수 있지만 위의 시나리오에서는 많이 구매할 것이라고 생각하지 않습니다. 스레드와 더 쉽게 상호 작용할 수 있도록 도와줍니다 (위의 시나리오에서는


나는 멋진 새로운 병렬 처리의 대부분이 단기의 작은 세분화 된 작업을 중심으로 설계되었으며 장기 실행 스레드는 여전히 System.IO.Threading.Thread.
Ben Voigt 2012 년

4

아마도 당신이 예상했던 대답은 아니지만 .NET Micro Framework에 대해 코딩 할 때 항상 Thread를 사용합니다. MF는 상당히 줄였고 더 높은 수준의 추상화를 포함하지 않으며 Thread 클래스는 낮은 MHz CPU에서 성능의 마지막 비트를 가져와야 할 때 매우 유연합니다.


이봐, 그것은 실제로 꽤 좋은 예입니다! 감사. 새로운 기능을 지원하지 않는 프레임 워크에 대해서는 생각하지 않았습니다.
Tudor

3

Thread 클래스를 ADO.NET과 비교할 수 있습니다. 작업을 완료하는 데 권장되는 도구는 아니지만 구식이 아닙니다. 작업을 쉽게하기 위해 다른 도구가 그 위에 구축됩니다.

특히 필요한 기능을 제공하지 않는 경우 다른 것보다 Thread 클래스를 사용하는 것은 잘못이 아닙니다.


3

확실히 구식이 아닙니다.

멀티 스레드 앱의 문제는 제대로 작동하기가 매우 어렵 기 때문에 (종종 비 결정적 동작, 입력, 출력 및 내부 상태가 중요 함) 프로그래머는 프레임 워크 / 도구에 최대한 많은 작업을 푸시해야합니다. 그것을 추상화하십시오. 그러나 추상화의 필멸의 적은 성능입니다.

그래서 제 질문은 위의 구조 중 하나 대신 일반 오래된 Thread 객체를 사용하는 것이 필요하거나 유용한 경우가 있습니까?

심각한 성능 문제, 고성능 목표가있는 경우에만 스레드 및 잠금을 사용합니다.


3

나는 내가 뽑은 스레드를 카운트하고 제어해야 할 때 항상 Thread 클래스를 사용했습니다. 스레드 풀을 사용하여 모든 뛰어난 작업을 저장할 수 있다는 것을 알고 있지만 현재 수행중인 작업의 양이나 상태를 추적하는 좋은 방법을 찾지 못했습니다.

대신, 나는 컬렉션을 생성하고 그들을 스핀 업 한 후에 스레드를 그 안에 배치합니다. 스레드가하는 가장 마지막 일은 컬렉션에서 자신을 제거하는 것입니다. 이렇게하면 항상 실행중인 스레드 수를 알 수 있고 컬렉션을 사용하여 각각의 작업을 물어볼 수 있습니다. 만약 내가 그들을 모두 죽여야하는 경우가 있다면, 일반적으로 당신은 당신의 응용 프로그램에 일종의 "Abort"플래그를 설정해야 할 것입니다. 모든 스레드가 스스로 그것을 알아 채고 스스로 종료 할 때까지 기다려야합니다. 제 경우에는, 저는 컬렉션을 살펴보고 각각에 대해 Thread.Abort를 차례로 발행 할 수 있습니다.

이 경우 Thread 클래스로 직접 작업하는 더 좋은 방법을 찾지 못했습니다. Eric Lippert가 언급했듯이 나머지는 고수준 추상화 일 뿐이며 사용 가능한 고수준 구현이 사용자의 요구를 충족하지 못할 때 저수준 클래스로 작업하는 것이 적절합니다. .NET이 정확한 요구 사항을 해결하지 못할 때 가끔 Win32 API 호출을 수행해야하는 것처럼 최근의 "진보"에도 불구하고 Thread 클래스가 최선의 선택 인 경우가 항상 있습니다.

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