(Примечание: я начал вводить это как комментарий, но, получив дополнительные знания во время исследования, он стал достаточно большим для ответа)
1. ThreadPool.QueueUserWorkItem
Первые две ссылки, которые предоставляет @ram, а также ответ @Bryan Batchelders, используют противоречивый ThreadPool.QueueUserWorkItem. Это противоречиво в контексте ASP.NET, потому что неосторожное использование может истощить пул потоков , как показывает @Perhentian ссылка .
2. BeginInvoke
Затем я посмотрел на третью ссылку @ram , в которой используется BeginInvoke. По сути, это просто говорит о том, что некоторый код запускается и в другом потоке . Так что здесь нет разрешения.
3. BeginGetResponse
Теперь вернемся к @Perhentians ссылка . В нем говорится, что BeginGetResponse несколько отличается от реального потока, поскольку он использует IOPC Completion Ports (IOPCs) . То, что вы на самом деле ищете, - это решение, которое все еще использует эти IOPC без создания дополнительного потока.
Теперь, чтобы увидеть, как .NET делает это, я попытался покопаться в HttpWebRequest.BeginGetResponse, который действительно является набором внутренних вызовов. Это идет как:
- HttpWebRequest.BeginGetResponse
- ServicePoint.SubmitRequest
- Connection.SubmitRequest
- Два варианта:
- Если соединение установлено: Connection.StartRequest
- В противном случае: Connection.WaitList.Add (запрос)
A. * 1047 лист ожидания *
Сначала рассмотрим вариант 2: указанный WaitList обрабатывается, когда соединение установлено с предыдущим запросом. Взглянув на ConnectStream, участвующий во всей этой цепочке, вы увидите ThreadPool.QueueUserWorkItem с замечанием:
// otherwise we queue a work item to parse the chunk
// Consider: Will we have an issue of thread dying off
// if we make a IO Read from that thread???
Таким образом, по крайней мере, в некоторых сценариях откатов потоки могут все еще непреднамеренно порождаться платформой, просто используя BeginGetResponse!
B. Connection.StartRequest
Теперь у нас все еще есть сценарий, где связь ясна. Обратный вызов устанавливается System.Net.Sockets.Socket.BeginConnect и фактически вызывается BeginAccept. Еще несколько копаний показывают вызов ThreadPool.UnsafeRegisterWaitForSingleObject, результат которого используется для ожидания.
Заключение
Наконец, мы можем сказать, что на самом деле происходит при выполнении BeginGetResponse:
// 1. Connecting a socket
UnsafeNclNativeMethods.OSSOCK.WSAConnect(m_handle)
// 2. Registering the callback
m_RegisteredWait = ThreadPool.UnsafeRegisterWaitForSingleObject(m_AsyncEvent, s_RegisteredWaitCallback, this, Timeout.Infinite, true);
// 3. Waiting for the socket to complete
UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(m_handle, m_AsyncEvent.SafeWaitHandle, blockEventBits);
Обратите внимание на Timeout.Infinite . Я все еще выясняю, возможно ли получить сокет, на котором выполняется кодовая дорожка, которая не выполняет ожидание, но сейчас мне это кажется невозможным.
Что касается моего заключения: похоже, не существует простого способа использовать IOCP в сценарии «забей и забудь». Поэтому, если вы не можете заставить указанный сокет не ждать завершения в BeginAccept, вы застряли в ThreadPool.