트래픽이 많은 시나리오에서 ASP.NET에서 ThreadPool.QueueUserWorkItem 사용


111

저는 항상 ThreadPool을 사용하여 (중요하지 않은) 단기 백그라운드 작업이 ASP.NET에서도 모범 사례로 간주된다는 인상을 받았습니다. 그러나 다른 방법을 제안하는 것처럼 보이는 이 기사 를 보았습니다. ASP.NET 관련 요청을 처리하려면 ThreadPool을 떠나야합니다.

지금까지 작은 비동기 작업을 수행 한 방법은 다음과 같습니다.

ThreadPool.QueueUserWorkItem(s => PostLog(logEvent))

그리고 기사는 명시 적으로 유사한 스레드를 생성하는 대신에 제안한다 :

new Thread(() => PostLog(logEvent)){ IsBackground = true }.Start()

첫 번째 방법은 관리되고 제한된다는 이점이 있지만, 백그라운드 작업이 ASP.NET 요청 처리기를 사용하여 스레드를두고 경쟁 할 가능성이 있습니다 (문서가 올바른 경우). 두 번째 방법은 ThreadPool을 해제하지만 제한이 없어서 잠재적으로 너무 많은 리소스를 사용할 수 있습니다.

그래서 제 질문은 기사의 조언이 맞습니까?

사이트에 트래픽이 너무 많아서 ThreadPool이 가득 차면 대역 외로 이동하는 것이 더 낫거나 전체 ThreadPool이 어쨌든 리소스의 한계에 도달하고 있음을 의미합니다. 자신의 스레드를 시작하려고하지 않아야합니까?

설명 : 별도의 프로세스가 필요한 값 비싼 작업 항목이 아닌 소규모의 중요하지 않은 비동기 작업 (예 : 원격 로깅)의 범위에서 요청하는 것입니다 (이 경우 더 강력한 솔루션이 필요하다는 데 동의합니다).


줄거리가 두꺼워집니다.이 기사를 찾았습니다 ( blogs.msdn.com/nicd/archive/2007/04/16/… ). 해독 할 수 없습니다. 한편으로는 IIS 6.0+가 항상 스레드 풀 작업자 스레드에서 요청을 처리한다고 말하는 것 같지만 (이전 버전 그렇게 할 수 있음) 다음과 같은 내용이 있습니다. "하지만 새로운 .NET 2.0 비동기 페이지를 사용하는 경우 ( Async = "true") 또는 ThreadPool.QueueUserWorkItem ()이면 처리의 비동기 부분이 [완료 포트 스레드] 내에서 수행됩니다. " 처리의 비동기 부분 ?
Jeff Sternal

다른 한 가지-이것은 스레드 풀의 사용 가능한 작업자 스레드가 최대 작업자 스레드보다 낮은 지 여부를 검사 한 다음 대기중인 내부에서 동일한 작업을 수행하여 IIS 6.0 이상 설치 (지금은 없음)에서 테스트 할 수있을만큼 쉽습니다. 작업 항목.
Jeff Sternal

답변:


104

여기에 다른 답변은 가장 중요한 점을 생략 한 것 같습니다.

부하가 적은 사이트에서 더 빠르게 수행하기 위해 CPU 집약적 인 작업을 병렬화하려고하지 않는 한 작업자 스레드를 사용할 필요가 없습니다.

에 의해 생성 된 사용 가능한 스레드 new Thread(...)와 요청에 ThreadPool응답하는 의 작업자 스레드 모두에 적용 QueueUserWorkItem됩니다.

예, 사실 입니다. 너무 많은 작업 항목을 대기열에 추가하여 ASP.NET 프로세스에서 굶주릴 ThreadPool 있습니다. ASP.NET이 추가 요청을 처리하지 못하게합니다. 기사의 정보는 그 점에서 정확합니다. QueueUserWorkItem요청을 처리하는 데에도 사용 되는 동일한 스레드 풀이 사용됩니다 .

그러나 실제로 이러한 기아를 유발할 수있는 충분한 작업 항목을 큐에 넣는 경우 스레드 풀이 부족 해야 합니다! 말 그대로 수백 개의 CPU 집약적 작업을 동시에 실행하는 경우 컴퓨터가 이미 과부하 상태 일 때 ASP.NET 요청을 처리 할 다른 작업자 스레드가 있으면 어떤 이점이 있습니까? 이런 상황에 처해 있다면 완전히 재 설계해야합니다!

대부분의 경우 멀티 스레드 코드가 ASP.NET에서 부적절하게 사용되는 것을 보거나 듣습니다. CPU 집약적 인 작업을 대기열에 넣는 것이 아닙니다. I / O 바운드 작업을 큐잉하기위한 것입니다. 그리고 당신은 내가에게 / O 작업을 수행하려는 경우, 당신은 I / O 스레드 (I / O 완료 포트)를 이용해야한다.

특히, 사용중인 라이브러리 클래스에서 지원하는 비동기 콜백을 사용해야합니다. 이러한 방법은 항상 매우 명확하게 표시되어 있습니다. 단어 BeginEnd. 마찬가지로 Stream.BeginRead, Socket.BeginConnect, WebRequest.BeginGetResponse, 등.

이러한 방법은 를 사용 ThreadPool하지만, 그들은 않습니다 IOCPs 사용 하지 ASP.NET 요청을 방해합니다. I / O 시스템의 인터럽트 신호에 의해 "깨어날"수있는 특수한 종류의 경량 스레드입니다. 그리고 ASP.NET 응용 프로그램에서는 일반적으로 각 작업자 스레드에 대해 하나의 I / O 스레드가 있으므로 모든 단일 요청에 하나의 비동기 작업이 대기 될 수 있습니다. 이는 상당한 성능 저하없이 말 그대로 수백 개의 비동기 작업입니다 (I / O 하위 시스템이이를 따라갈 수 있다고 가정). 여러분이 필요로하는 것보다 훨씬 더 많습니다.

비동기 델리게이트 는 이런 방식으로 작동하지 않는다는 점을 명심하십시오. .NET 과 마찬가지로 작업자 스레드를 사용하게 ThreadPool.QueueUserWorkItem됩니다. 이 작업을 수행 할 수있는 것은 .NET Framework 라이브러리 클래스의 기본 제공 비동기 메서드뿐입니다. 직접 할 수 있지만 복잡하고 약간 위험하며 아마도이 논의의 범위를 벗어납니다.

이 질문에 대한 가장 좋은 대답 은 ASP.NET에서 또는 백그라운드 인스턴스를 사용하지 않는 것ThreadPool Thread 입니다. Windows Forms 응용 프로그램에서 스레드를 회전시키는 것과는 전혀 다릅니다. UI의 응답 성을 유지하고 얼마나 효율적인지 신경 쓰지 않습니다. ASP.NET에서 관심사는 처리량 이며 모든 작업자 스레드에서 전환되는 모든 컨텍스트는 사용 여부에 관계없이 처리량 을 절대적으로 죽일ThreadPool입니다.

ASP.NET에서 스레딩 코드를 작성하는 경우-기존 비동기 메서드를 사용하도록 다시 작성할 수 있는지 여부를 고려하고 그렇지 않은 경우 실제로 코드가 필요한지 여부를 고려하십시오. 백그라운드 스레드에서 실행됩니다. 대부분의 경우 순이익이없이 복잡성을 추가 할 수 있습니다.


자세한 응답에 감사 드리며 귀하의 말이 맞습니다. 가능한 경우 비동기 메서드를 시도하고 사용합니다 (ASP.NET MVC의 비동기 컨트롤러와 결합). 내 예의 경우 원격 로거를 사용하면 이것이 정확히 내가 할 수있는 일입니다. 컨트롤러 수준 (후자의 경우)에서 결정할 수있는 대신 비동기 처리를 코드의 최하위 수준 (예 : 로거 구현)까지 푸시하기 때문에 흥미로운 디자인 문제입니다. , 예를 들어 선택할 수있는 두 개의 로거 구현이 필요합니다).
Michael Hart

@Michael : 비동기 콜백은 일반적으로 더 많은 레벨을 올리려는 경우 래핑하기가 매우 쉽습니다. 예를 들어 비동기 메서드 주위에 파사드를 만들고를 Action<T>콜백으로 사용하는 단일 메서드로 래핑 할 수 있습니다 . 작업자 스레드를 사용할지 I / O 스레드를 사용할지 선택하는 것이 가장 낮은 수준에서 발생한다는 것을 의미한다면 이는 의도적 인 것입니다. 해당 레벨 만이 IOCP가 필요한지 여부를 결정할 수 있습니다.
Aaronaught 2010

관심의 대상으로, ThreadPool이러한 방식으로 당신을 제한하는 것은 오직 .NET뿐입니다. 아마도 그들은 개발자들이 그것을 제대로 할 것이라고 믿지 않았기 때문일 것입니다. 관리되지 않는 Windows 스레드 풀에는 매우 유사한 API가 있지만 실제로 스레드 유형을 선택할 수 있습니다.
Aaronaught 2010-04-15

2
I / O 완료 포트 (IOCP). IOCP에 대한 설명이 정확하지 않습니다. IOCP에는 모든 보류중인 작업에서 교대로 작동하는 작업자 스레드 수가 고정되어 있습니다. 크기가 고정되거나 동적 일 수 있지만 작업 당 하나의 스레드가있는 스레드 풀과 혼동하지 마십시오. ASYNC와 달리 작업 당 하나의 스레드가 없습니다. IOCP 스레드는 작업 1에서 약간 작동 한 다음 작업 3, 작업 2로 전환 한 다음 다시 작업 1로 돌아갈 수 있습니다. 작업 세션 상태가 저장되고 스레드간에 전달됩니다.
MickyD

1
데이터베이스 삽입은 어떻습니까? ASYNC SQL 명령 (예 : Execute)이 있습니까? 데이터베이스 삽입은 (잠금으로 인해) 가장 느린 I / O 작업에 대한 것이며 주 스레드가 행이 삽입 될 때까지 기다리게하는 것은 CPU주기를 낭비하는 것입니다.
Ian Thompson

45

Microsoft ASP.NET 팀의 Thomas Marquadt에 따르면 ASP.NET ThreadPool (QueueUserWorkItem)을 사용하는 것이 안전합니다.

기사에서 :

Q) 내 ASP.NET 응용 프로그램이 CLR ThreadPool 스레드를 사용하는 경우 요청을 실행하는 데 CLR ThreadPool을 사용하는 ASP.NET도 사용하지 않습니까? ..

A) 요약하자면 ASP.NET의 스레드가 부족 할까 걱정하지 마세요. 여기에 문제가 있다고 생각되면 알려 주시면 처리해 드리겠습니다.

Q) 나만의 스레드 (새 스레드)를 만들어야합니까? CLR ThreadPool을 사용하기 때문에 ASP.NET에 더 적합하지 않을 것입니다.

A)하지 마십시오. 아니면 다른 방식으로 말하면 안돼 !!! 당신이 정말 똑똑하다면-나보다 훨씬 똑똑하다면-당신 자신의 스레드를 만들 수 있습니다. 그렇지 않으면 그것에 대해 생각하지 마십시오. 새 스레드를 자주 생성하지 않아야하는 몇 가지 이유는 다음과 같습니다.

  1. QueueUserWorkItem에 비해 매우 비쌉니다. 그런데 CLR보다 더 나은 ThreadPool을 작성할 수 있다면 Microsoft에 지원하는 것이 좋습니다.

4

웹 사이트는 스레드 생성 주변으로 이동해서는 안됩니다.

일반적으로이 기능을 Windows 서비스로 이동 한 다음 통신 할 수 있습니다 (MSMQ를 사용하여 통신합니다).

-- 편집하다

여기서 구현에 대해 설명했습니다. ASP.NET MVC 웹 응용 프로그램의 큐 기반 백그라운드 처리

-- 편집하다

이것이 스레드보다 더 나은 이유를 확장하려면 :

MSMQ를 사용하여 다른 서버와 통신 할 수 있습니다. 여러 컴퓨터에서 대기열에 쓸 수 있으므로 어떤 이유로 백그라운드 작업이 주 서버의 리소스를 너무 많이 사용하고 있다고 판단되면 아주 사소하게 이동할 수 있습니다.

또한하려고했던 모든 작업을 일괄 처리 할 수 ​​있습니다 (이메일 보내기 / 무엇이든).


4
저는이 포괄적 인 진술이 항상 사실이라는 데 동의하지 않습니다. 특히 중요하지 않은 작업의 경우에는 더욱 그렇습니다. 비동기 로깅의 목적으로 Windows 서비스를 만드는 것은 분명히 과잉으로 보입니다. 게다가이 옵션을 항상 사용할 수있는 것은 아닙니다 (MSMQ 및 / 또는 Windows 서비스를 배포 할 수 있음).
Michael Hart

물론입니다.하지만 웹 사이트에서 비동기 작업을 구현하는 '표준'방법입니다 (다른 프로세스에 대한 대기열 테마).
Noon Silk

2
모든 비동기 작업이 동일하게 생성되는 것은 아니므로 예를 들어 ASP.NET에 비동기 페이지가 존재합니다. 표시 할 원격 웹 서비스에서 결과를 가져 오려면 MSMQ를 통해 수행하지 않습니다. 이 경우 원격 게시물을 사용하여 로그에 쓰고 있습니다. Windows 서비스를 작성하거나 MSMQ를 연결하는 것은 문제에 적합하지 않습니다 (이 특정 앱이 Azure에 있으므로 나도 마찬가지입니다).
Michael Hart

1
고려 : 원격 호스트에 쓰고 있습니까? 해당 호스트가 다운되었거나 연결할 수없는 경우 어떻게합니까? 쓰기를 다시 시도 하시겠습니까? 아마 당신은 그렇지 않을 것입니다. 구현하면 다시 시도하기가 어렵습니다. 서비스를 사용하면 매우 사소 해집니다. 나는 당신이 그것을 할 수 없을 수도 있다는 것에 감사하고, 나는 다른 사람이 웹 사이트에서 스레드를 생성하는 특정 문제에 대해 대답하도록 할 것이다 [즉, 당신의 스레드가 배경이 아닌 경우 등], 그러나 나는 '적절한' 그것을하는 방법. ec2를 사용했지만 azure에 익숙하지 않습니다 (OS를 설치할 수 있으므로 아무 문제가 없습니다).
Noon Silk

@silky, 의견 주셔서 감사합니다. 이 더 무거운 (아직 내구성이있는) 솔루션을 피하기 위해 "중요하지 않음"이라고 말했습니다. 대기중인 작업 항목에 대한 모범 사례를 요구하지 않는 것이 분명하도록 질문을 명확히했습니다. Azure는 이러한 유형의 시나리오를 지원합니다 (자체 큐 저장소가 있음).하지만 큐 작업은 동기 로깅에 비해 너무 비싸기 때문에 어쨌든 비동기 솔루션이 필요합니다. 제 경우에는 실패의 함정을 알고 있지만이 특정 로깅 공급자가 실패 할 경우를 대비하여 인프라를 추가하지 않을 것입니다. 다른 로깅 공급자도 있습니다.
Michael Hart

4

ASP.NET에서 빠르고 우선 순위가 낮은 비동기 작업을위한 일반적인 방법은 특히 리소스를 제한하려는 트래픽이 많은 시나리오에서 .NET 스레드 풀을 사용하는 것입니다.

또한 스레딩 구현이 숨겨져 있습니다. 자신의 스레드를 생성하기 시작하면 스레드도 제대로 관리해야합니다. 할 수 없다는 말이 아니라 왜 그 바퀴를 재발 명할까요?

성능이 문제가되고 스레드 풀이 제한 요소 (데이터베이스 연결, 나가는 네트워크 연결, 메모리, 페이지 시간 초과 등이 아님)임을 확인할 수있는 경우 스레드 풀 구성을 조정하여 더 많은 작업자 스레드, 더 많은 대기 요청을 허용합니다. 등

성능 문제가없는 경우 ASP.NET 요청 큐와의 경합을 줄이기 위해 새 스레드를 생성하도록 선택하는 것은 고전적인 조기 최적화입니다.

이상적으로는 로깅 작업을 수행하기 위해 별도의 스레드를 사용할 필요가 없습니다. 원래 스레드가 가능한 한 빨리 작업을 완료하도록 설정하면 MSMQ와 별도의 소비자 스레드 / 프로세스가 표시됩니다. 이 작업이 더 무겁고 구현해야 할 작업이 더 많다는 데 동의하지만 여기서는 내구성이 정말 필요합니다. 공유 된 인 메모리 대기열의 변동성은 빠르게 환영을 잃을 것입니다.


2

QueueUserWorkItem을 사용하고 전염병을 피하는 것처럼 새 스레드를 생성하지 않아야합니다. ASP.NET이 동일한 ThreadPool을 사용하기 때문에 ASP.NET을 굶주 리지 않는 이유를 설명하는 비주얼을 보려면 두 손을 사용하여 6 개의 볼링 핀, 검 또는 비행 중에 무엇이든 유지하는 매우 숙련 된 요술쟁이를 상상해보십시오. 자신의 스레드를 만드는 것이 왜 나쁜지 시각적으로 보려면 고속도로 진입로를 많이 사용하여 차량이 조명을 사용하고 입구 수를 몇 초마다 1 개로 제한하는 대신 차량이 즉시 교통에 진입 할 수 있도록하는 러시아워에 시애틀에서 어떤 일이 발생하는지 상상해보십시오. . 마지막으로 자세한 설명은 다음 링크를 참조하십시오.

http://blogs.msdn.com/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx

고마워, 토마스


그 링크는 매우 유용합니다. 토마스에게 감사합니다. @Aaronaught의 반응에 대해 어떻게 생각하는지 듣고 싶습니다.
Michael Hart

나는 Aaronaught에 동의하며 내 블로그 게시물에서도 똑같이 말했습니다. "이 결정을 단순화하기 위해 아무것도하지 않는 동안 ASP.NET 요청 스레드를 차단하려는 경우에만 [다른 스레드로] 전환해야합니다. 이것은 지나치게 단순화 된 것입니다. 결정을 간단하게합니다. " 즉, 비 차단 계산 작업을 위해 수행하지 말고 원격 서버에 대한 비동기 웹 서비스 요청을 수행하는 경우 수행하십시오. Aaronaught를 들어라! :)
Thomas

1

그 기사는 정확하지 않습니다. ASP.NET에는 ASP.NET 요청을 처리하기위한 자체 스레드 풀 (관리 작업자 스레드)이 있습니다. 이 풀은 일반적으로 수백 개의 스레드이며 ThreadPool 풀과는 별개입니다.이 풀은 프로세서의 일부 더 작은 배수입니다.

ASP.NET에서 ThreadPool을 사용하면 ASP.NET 작업자 스레드를 방해하지 않습니다. ThreadPool을 사용하는 것이 좋습니다.

메시지를 로깅하고 생산자 / 소비자 패턴을 사용하여 해당 스레드에 로그 메시지를 전달하는 단일 스레드를 설정하는 것도 허용됩니다. 이 경우 스레드의 수명이 길기 때문에 로깅을 실행하려면 단일 새 스레드를 만들어야합니다.

모든 메시지에 대해 새 스레드를 사용하는 것은 확실히 과잉입니다.

로깅에 대해서만 이야기하는 경우 또 다른 대안은 log4net과 같은 라이브러리를 사용하는 것입니다. 별도의 스레드에서 로깅을 처리하고 해당 시나리오에서 발생할 수있는 모든 컨텍스트 문제를 처리합니다.


1
@Sam, 실제로 log4net을 사용하고 있으며 별도의 스레드에 기록되는 로그가 표시되지 않습니다. 활성화해야하는 옵션이 있습니까?
Michael Hart

1

기사가 틀렸다고 말하고 싶습니다. 대규모 .NET 상점을 운영하는 경우 ThreadPool 설명서의 한 문장을 기반으로 여러 앱과 여러 웹 사이트 (별도의 앱 풀 사용)에서 안전하게 풀을 사용할 수 있습니다 .

프로세스 당 하나의 스레드 풀이 있습니다. 스레드 풀의 기본 크기는 사용 가능한 프로세서 당 250 개의 작업자 스레드와 1000 개의 I / O 완료 스레드입니다. 스레드 풀의 스레드 수는 SetMaxThreads 메서드를 사용하여 변경할 수 있습니다. 각 스레드는 기본 스택 크기를 사용하고 기본 우선 순위로 실행됩니다.


단일 프로세스에서 실행되는 하나의 응용 프로그램은 완전히 중단 될 수 있습니다! (또는 적어도 스레드가지는 제안을 풀 수 있도록 자신의 성능을 충분히 저하.)
제프 흉골

그래서 ASP.NET 요청이 작업자 스레드와 달리 I / O 완료 스레드를 사용한다고 생각합니다. 맞습니까?
Michael Hart

Fritz Onion의 기사에서 "이 패러다임은 [IIS 5.0에서 IIS 6.0으로] 요청이 ASP.NET에서 처리되는 방식을 변경합니다. inetinfo.exe에서 ASP.NET 작업자 프로세스 인 http로 요청을 발송하는 대신. sys는 적절한 프로세스에서 각 요청을 직접 대기열에 넣습니다. 따라서 모든 요청은 이제 CLR 스레드 풀에서 가져온 작업자 스레드에 의해 처리되고 I / O 스레드에서는 처리되지 않습니다 . " (내 강조)
제프 흉골

흠, 아직 완전히 확실하지 않습니다 ... 그 기사는 2003 년 6 월의 것입니다. 2004 년 5 월에이 기사를 읽으면 (아직도 꽤 오래된 것임) "Sleep.aspx 테스트 페이지는 ASP를 유지하는 데 사용할 수 있습니다. .NET I / O thread busy ", 여기서 Sleep.aspx로 인해 현재 실행중인 스레드가 절전 모드로 전환됩니다. msdn.microsoft.com/en-us/library/ms979194.aspx- 기회가있을 때 확인할 수 있습니다. 이 예제를 코딩하고 IIS 7 및 .NET 3.5에서 테스트 할 수 있다면
Michael Hart

네, 그 단락의 텍스트가 혼란 스럽습니다. 이 섹션을 더 진행하면 내용 을 명확히 하는 지원 항목 ( support.microsoft.com/default.aspx?scid=kb;EN-US;816829 )으로 연결됩니다. I / O 완료 스레드에서 요청을 실행하는 것은 .NET Framework 1.0이었습니다. ASP.NET 1.1 2003 년 6 월 핫픽스 롤업 패키지에서 수정 된 문제 (이후 "모든 요청이 이제 작업자 스레드에서 실행 됨"). 더 중요한 것은이 예제는 ASP.NET 스레드 풀이 System.Threading.ThreadPool.
Jeff Sternal

1

지난주 직장에서 비슷한 질문을 받았는데 같은 답을 드리겠습니다. 요청 당 웹 애플리케이션을 다중 스레딩하는 이유는 무엇입니까? 웹 서버는 적시에 많은 요청을 제공하도록 최적화 된 환상적인 시스템입니다 (예 : 멀티 스레딩). 웹에서 거의 모든 페이지를 요청할 때 어떤 일이 발생하는지 생각해보십시오.

  1. 일부 페이지에 대한 요청이 있습니다.
  2. HTML이 다시 제공됩니다.
  3. Html은 클라이언트에게 추가 요청 (js, css, 이미지 등)을 만들도록 지시합니다.
  4. 추가 정보가 다시 제공됩니다.

원격 로깅의 예를 제공하지만 이는 로거의 문제입니다. 메시지를 적시에 수신하려면 비동기 프로세스가 있어야합니다. Sam은 로거 (log4net)가 이미이를 지원해야한다고 지적합니다.

Sam은 CLR에서 스레드 풀을 사용하더라도 IIS의 스레드 풀에 문제가 발생하지 않는다는 점에서도 정확합니다. 여기서 염려해야 할 것은 프로세스에서 스레드를 생성하는 것이 아니라 IIS 스레드 풀 스레드에서 새 스레드를 생성한다는 것입니다. 차이가 있고 구별이 중요합니다.

스레드 대 프로세스

스레드와 프로세스는 모두 응용 프로그램을 병렬화하는 방법입니다. 그러나 프로세스는 자체 상태 정보를 포함하고 자체 주소 공간을 사용하며 프로세스 간 통신 메커니즘 (일반적으로 운영 체제에서 관리)을 통해서만 서로 상호 작용하는 독립적 인 실행 단위입니다. 애플리케이션은 일반적으로 설계 단계에서 프로세스로 나뉘며, 마스터 프로세스는 중요한 애플리케이션 기능을 논리적으로 분리하는 것이 합리적 일 때 명시 적으로 하위 프로세스를 생성합니다. 즉, 프로세스는 아키텍처 구조입니다.

반대로 스레드는 응용 프로그램의 아키텍처에 영향을주지 않는 코딩 구조입니다. 단일 프로세스에 여러 스레드가 포함될 수 있습니다. 프로세스 내의 모든 스레드는 동일한 상태와 동일한 메모리 공간을 공유하며 동일한 변수를 공유하기 때문에 서로 직접 통신 할 수 있습니다.

출처


3
@Ty, 입력 해 주셔서 감사합니다.하지만 웹 서버가 어떻게 작동하는지 잘 알고 있으며 질문과 실제로 관련이 없습니다. 다시 질문에서 말했듯이 아키텍처로서 이것에 대한 지침을 요청하지 않습니다. 발행물. 특정 기술 정보를 요청하고 있습니다. 이미 비동기 프로세스가 있어야하는 "로거의 관심사"라는 점에 관해서는-로거 구현에서 비동기 프로세스를 작성해야한다고 어떻게 생각하십니까?
Michael Hart

0

참조 된 문서 (C # feeds.com)에 동의하지 않습니다. 새 스레드를 만드는 것은 쉽지만 위험합니다. 단일 코어에서 실행하기위한 최적의 활성 스레드 수는 실제로 놀랍게도 10 개 미만입니다. 사소한 작업을 위해 스레드가 생성 된 경우 시스템이 스레드 전환 시간을 낭비하게 만드는 것은 너무 쉽습니다. 스레드는 관리가 필요한 리소스입니다. WorkItem 추상화가이를 처리합니다.

요청에 사용할 수있는 스레드 수를 줄이는 것과 스레드 중 하나가 효율적으로 처리 할 수 ​​있도록 너무 많은 스레드를 만드는 것 사이에는 트레이드 오프가 있습니다. 이것은 매우 동적 인 상황이지만 스레드 생성에 앞서 처리하기 위해 처리자에게 맡기지 말고 적극적으로 관리 (이 경우 스레드 풀에 의해)되어야한다고 생각합니다.

마지막으로이 기사는 ThreadPool 사용의 위험성에 대해 꽤 포괄적 인 진술을하지만 실제로이를 백업하기 위해서는 구체적인 무언가가 필요합니다.


0

IIS가 동일한 ThreadPool을 사용하여 들어오는 요청을 처리하는지 여부에 대한 명확한 답변을 얻기 어렵고 버전에 따라 변경된 것으로 보입니다. 따라서 IIS에서 많은 스레드를 사용할 수 있도록 ThreadPool 스레드를 과도하게 사용하지 않는 것이 좋습니다. 반면에 모든 작은 작업에 대해 자신의 스레드를 생성하는 것은 나쁜 생각처럼 보입니다. 아마도 로깅에 일종의 잠금이 있으므로 한 번에 하나의 스레드 만 진행할 수 있고 나머지는 일정이 잡히고 일정이 잡히지 않고 번갈아 가며 새 스레드를 생성하는 오버 헤드는 말할 것도 없습니다. 기본적으로 ThreadPool이 방지하도록 설계된 정확한 문제에 직면하게됩니다.

합리적인 타협은 메시지를 전달할 수있는 단일 로깅 스레드를 앱에 할당하는 것 같습니다. 앱 속도를 늦추지 않도록 메시지 전송이 가능한 한 빠르도록주의해야합니다.


0

Parallel.For 또는 Parallel.ForEach를 사용하고 원활하게 실행하고 풀 고갈을 방지하기 위해 할당 할 가능한 스레드의 제한을 정의 할 수 있습니다.

그러나 백그라운드에서 실행하려면 ASP.Net 웹 응용 프로그램에서 아래의 순수한 TPL 스타일을 사용해야합니다.

var ts = new CancellationTokenSource();
CancellationToken ct = ts.Token;

ParallelOptions po = new ParallelOptions();
            po.CancellationToken = ts.Token;
            po.MaxDegreeOfParallelism = 6; //limit here

 Task.Factory.StartNew(()=>
                {                        
                  Parallel.ForEach(collectionList, po, (collectionItem) =>
                  {
                     //Code Here PostLog(logEvent);
                  }
                });
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.