2017-12-10 8 views
6

I/O 완료 포트를 이해하려고합니다. 구체적으로 I/O에 async - await을 사용하는 것과 관련이 있습니다.IOCP는 입출력이 진행되는 동안 실행중인 스레드입니까?

악명 높은 제품 There is No Thread은 입출력이 완료된 후 잠깐 차용 한 IOCP에 대해 이야기합니다. 이 글의 요점은 멋진 하드웨어 수준의 I/O가 기내에있을 때 루프처럼 소모되는 스레드가 없다는 것을 보여주는 것입니다.

I/O 완료 여부 ? 아닙니다. I/O는 아직 완료 되었습니까? 아닙니다. I/O는 아직 완료 되었습니까? 호 ...

그러나 그 다음 나는

"구성 요소가 대기 요소의 완료 포트를 확인 담당하고있다"고 말했다되는 this article 찾고 있어요 예를 들면 다음과 같습니다.

public class IOCompletionWorker 
{ 
    public unsafe void Start(IntPtr completionPort) 
    { 
     while (true) 
     { 
      uint bytesRead; 
      uint completionKey; 
      NativeOverlapped* nativeOverlapped; 

      var result = Interop.GetQueuedCompletionStatus(
       completionPort, 
       out bytesRead, 
       out completionKey, 
       &nativeOverlapped, 
       uint.MaxValue); 

      var overlapped = Overlapped.Unpack(nativeOverlapped); 

      if (result) 
      { 
       var asyncResult = ((FileReadAsyncResult)overlapped.AsyncResult); 
       asyncResult.ReadCallback(bytesRead, asyncResult.Buffer); 
      } 
      else 
      { 
       ThreadLogger.Log(Interop.GetLastError().ToString()); 
      } 

      Overlapped.Free(nativeOverlapped); 
     } 
    } 
} 

var completionPortThread = new Thread(() => new IOCompletionWorker().Start(completionPortHandle)) 
{ 
    IsBackground = true 
}; 
completionPortThread.Start(); 

내게는 폴링이 진행되는 것처럼 보입니다. (2) "I/O (1)"작업자 스레드 "와 -

나는 그것이 .NET 응용 프로그램이 스레드 풀의 2 개 종류가 있다는 말을 사실인가요 내 질문

  • 졸이다 것 같아요 스레드 "?
  • 사실 일 경우 작업자 스레드와 N 개의 I/O 스레드와 같이 구성에 고정 된 번호가 지정되어 있습니까? 그리고 대개 M 대 N의 비율은 무엇입니까?
  • 정확하게 I/O 스레드가 사용되는 시점은 언제입니까?
+0

질문에 대한 답변을 얻었습니까? :) – fbrosseau

답변

5

두 기사는 모두 독자적인 방식으로되어 있습니다.

IOCP는 스레드가 아닙니다. 그것들은 커널 (또는 PostQueuedCompletionStatus를 통한 일반 사용자 모드 코드)이 완료 항목을 게시 할 수있는 일종의 대기열로 볼 수 있습니다. 고유 한 스레딩 모델이나 IOCP 자체와 관련된 스레드는 없으며 단순히 여러 개의 생성자 - 대기열입니다.

가의 예로 들어 네트워크 소켓을 보자, 그러나 이것은 비동기 작업의 모든 종류의 사실 일 것입니다 :

  • 당신이 IOCP에 결합하여 중복 모드 소켓에되었던 WSARecv를 호출, 네트워크에 달려 드라이버는 실제 데이터 수신 요청을 설정하는 데 필요한 모든 작업을 수행합니다. 데이터가 도착할 때까지 기다리는 스레드가 없습니다.
  • 데이터가 도착합니다. 운영 체제가 하드웨어에 의해 깨우쳐졌습니다. 운영 체제는 들어오는 이벤트를 처리하기 위해 커널의 일부 CPU 시간을 네트워크 드라이버에 제공합니다. 네트워크 드라이버가 인터럽트를 처리 한 다음 소켓이 IOCP에 바인딩 되었기 때문에 완료 항목을 IOCP 큐에 게시합니다. 요청이 완료되었습니다.

초기 비동기 호출 외에이 작업과 관련된 프로세스의 실제 사용자 모드 스레드가 없습니다. 데이터가 도착했다는 사실을 알고 싶다면 (소켓에서 읽는 중 사용자가 수행한다고 가정), IOCP에서 완료된 항목을 큐에서 제거해야합니다.

IOCP의 요점은 수천 개의 IO 핸들 (소켓, 파일 등)을 단일 IOCP에 바인딩 할 수 있다는 것입니다. 그런 다음 단일 스레드를 사용하여 수천 개의 비동기 프로세스를 병렬로 구동 할 수 있습니다.

예, GetQueuedCompletionStatus를 수행하는 스레드가 차단되어 IOCP에 보류중인 완료가 없으므로 혼동이 발생한 부분 일 수 있습니다. 그러나 IOCP의 요점은 특정 시간에 수십만 개의 네트워크 작업을 보류 할 수있는 동안 하나의 스레드를 차단한다는 것입니다. 모든 스레드는 한 스레드에서 처리합니다. IO handle/IOCP/Servicing Thread 간에는 1 : 1 대 1 맵핑을 사용하지 않을 것입니다. 비동기식으로 인해 얻을 수있는 이점을 잃어 버릴 것이고 동기식 IO를 사용할 수도 있기 때문입니다.

IOCP의 주요 포인트는 Windows에서 비동기 작업의 인상적인 병렬 처리를 달성하는 것입니다.

혼란을 분명히 밝히기를 바랍니다. 특정 질문에

  1. 예에 관해서는

    는 닷넷 프레임 워크는 2 개의 수영장이있다. 하나는 순전히 사용자 모드의 범용 작업 인 "Worker"스레드 풀입니다. 다른 하나는 "IO"스레드 풀입니다. 이 두 번째는 높은 수준의 C# 코드를 작성할 때 모든 IOCP 관리를 숨길 수 있으므로 비동기 소켓이 마술처럼 작동 할 수 있습니다.

  2. 이것은 언제든지 변경할 수있는 구현 세부 사항입니다. 그러나 대답은 두 풀이 모두 독립적이라는 것입니다. 작업자 스레드 풀에서 막대한 작업 대역폭이 발생하고 프레임 워크가 새 스레드를 추가하여 전반적인 처리량이 증가한다고 결정하면 작업자 풀에만 스레드를 추가하고 IO 풀은 변경하지 않습니다. IO 풀에 대해서도 마찬가지입니다. 콜백에서 IO 스레드를 차단하는 코드를 잘못 작성하면 새로운 IO 풀을 생성하고 작업자 풀에 손을 대지 않습니다. ThreadPool.SetMinThreads/SetMaxThreads를 사용하여 번호를 사용자 정의 할 수 있지만 일반적으로 프로세스가 스레드 풀을 오용하는 표시입니다.
  3. IO 스레드는 스레드 풀의 내부 IOCP에서 대기열에있는 항목이있을 때 사용됩니다. 일반적인 코드에서 이것은 비동기 작업이 일부 IO 핸들에서 완료되었을 때입니다. UnsafeQueueNativeOverlapped를 통해 항목을 직접 대기시킬 수도 있지만 그다지 흔하지는 않습니다.

순수 관리 비동기 작업 (일처럼 예를 들어, Task.Delay와 비동기를-기다리고 있습니다) 어떤 IO 핸들을 포함하지 않는, 그래서 그들은 어떤 드라이버에 의해 IOCP에 게시되고 결국하지 않는 등 그것들은 "노동자"범주에 속할 것입니다.

부수적으로, 호출 스레드별로 작업자 스레드에 IO 스레드를 알릴 수 있습니다. 작업 스레드는 "ThreadPoolWorkQueue.Dispatch"로 관리되는 호출 스택을 시작하지만 IO 스레드는 "_IOCompletionCallback.PerformIOCompletionCallback"으로 관리되는 호출 스택을 시작합니다. 이것은 언제든지 변경할 수있는 모든 구현 세부 사항이지만 관리 코드를 디버깅 할 때 무엇을 처리하는지 알면 도움이됩니다.