asp.net - method - static async task return
Async HttpWebRequest sin espera desde dentro de una aplicaciĆ³n web (3)
probablemente estés mirando el patrón "fuego y olvídate". Aquí hay algunos enlaces.
http://weblogs.asp.net/albertpascual/archive/2009/05/14/fire-and-forget-class-for-asp-net.aspx
http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx
http://www.eggheadcafe.com/articles/20060727.asp
espero que esto ayude
En mi aplicación web (ASP.NET) tengo un bloque de código que usa HttpWebRequest para hacer una llamada a un servicio REST y continuar la ejecución. En este momento me está tomando más tiempo de lo que me gustaría completar la solicitud web completa. Lo que pasa es que lo que devuelve el servicio REST no es útil. Idealmente, me gustaría enviar una solicitud web Async al servicio REST y luego NO esperar una respuesta. El problema es que lo probé usando
request.BeginGetResponse(New AsyncCallback(AddressOf myFunc), Nothing)
Para iniciar una solicitud asincrónica y en lugar de NO esperar (que asumiría que sería el comportamiento predeterminado de una solicitud asíncrona) ejecuta continuamente la función de devolución de llamada antes de ejecutar la siguiente línea de código después de BeginGetResponse
.
Sospecho que ASP.NET puede convertirlo a una solicitud de sincronización cuando está dentro de una aplicación web. Me hacen creer esto porque hay un objeto de IAsyncResult result
que se pasa a la función de devolución de llamada y cuando examino su propiedad CompletedSynchronously
siempre se establece en verdadero.
¿Alguien sabe si es posible hacer una async HttpWebRequest (sin esperar) desde una aplicación web ASP.NET o siempre se convierte en una solicitud síncrona?
(Nota: Empecé a ingresar esto como un comentario, pero a medida que adquirí un poco de conocimiento extra mientras investigaba, creció lo suficiente como para obtener una respuesta)
1. ThreadPool.QueueUserWorkItem
Los primeros dos enlaces que proporciona @ram, así como la respuesta de @Bryan Batchelders hacen uso del controvertido ThreadPool.QueueUserWorkItem. Es controvertido en el contexto de ASP.NET porque el uso poco cuidadoso puede privar a su grupo de subprocesos , como muestra el link @Perhentian.
2. BeginInvoke
Luego eché un vistazo al http://www.eggheadcafe.com/articles/20060727.asp @ ram, que hace uso de BeginInvoke. En esencia, esto parece indicarle a algún código que se ejecute en otro hilo también. Entonces no hay resolución aquí.
3. BeginGetResponse
Ahora volvamos al link @Perhentians. Establece cómo BeginGetResponse es algo diferente de un hilo real, porque utiliza IO Completion Ports (IOPC) . Entonces, lo que realmente está buscando, es una solución que todavía usa estos IOPC sin crear un hilo adicional.
Ahora, para ver cómo .NET hace esto, traté de profundizar en HttpWebRequest.BeginGetResponse, que en realidad es un trapo de llamadas internas. Es como:
- HttpWebRequest.BeginGetResponse
- ServicePoint.SubmitRequest
- Connection.SubmitRequest
- Dos opciones:
- Si la conexión es clara: Connection.StartRequest
- De lo contrario: Connection.WaitList.Add (solicitud)
A. lista de espera
Primero, consideremos la opción 2: dicha WaitList se procesa cuando se realiza una conexión con una solicitud anterior. Al echar un vistazo al ConnectStream involucrado en toda esta cadena, se muestra un ThreadPool.QueueUserWorkItem con la observación:
// 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???
Por lo tanto, al menos en algunos escenarios alternativos, los hilos aún pueden ser generados inadvertidamente por el framework, ¡simplemente utilizando BeginGetResponse!
B. Connection.StartRequest
Ahora, todavía tenemos el escenario donde la conexión es clara. La devolución de llamada es instalada por System.Net.Sockets.Socket.BeginConnect y realmente invocada por BeginAccept. Un poco más de excavación revela una llamada a ThreadPool.UnsafeRegisterWaitForSingleObject cuyo resultado se usa para esperar.
Conclusión
Finalmente, podemos decir qué está sucediendo realmente al hacer un 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);
Tenga en cuenta el tiempo de espera.Infinito . Todavía estoy investigando si es posible hacer que el socket ejecute un código de ruta que no realiza la espera, pero por ahora, me parece imposible.
En cuanto a mi conclusión: parece que no hay una manera fácil de usar IOCP en un escenario de Fire-For-Forget. Así que a menos que pueda hacer que el socket anterior no espere a que finalice en BeginAccept, se quedará atrapado con ThreadPool.
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(myUrl);
//set up web request...
ThreadPool.QueueUserWorkItem(o=>{ myRequest.GetResponse(); });
También conocido como Fire-and-Forget.