최신 구조 중 하나 대신 일반 오래된 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.