代码之家  ›  专栏  ›  技术社区  ›  Adam

在Web应用程序内不等待的异步httpwebrequest

  •  21
  • Adam  · 技术社区  · 15 年前

    在我的Web应用程序(ASP.NET)中,我有一个代码块,它使用httpwebrequest来调用REST服务并继续执行。现在,完成完整的Web请求所需的时间比我希望的要长。问题是,REST服务返回的内容并不有用。理想情况下,我希望向REST服务发送一个异步Web请求,然后不等待响应。问题是我用

    request.BeginGetResponse(New AsyncCallback(AddressOf myFunc), Nothing)
    

    为了启动一个异步请求,而不是等待(我假设这是异步请求的默认行为),它在执行之后的下一行代码之前连续地执行回调函数。 BeginGetResponse .

    我怀疑ASP.NET可能会在Web应用程序中将其转换为同步请求。我相信这是因为 IAsyncResult result 当我检查回调函数的 CompletedSynchronously 属性它始终设置为true。

    是否有人知道是否可以从ASP.NET Web应用程序中执行异步httpwebrequest(不等待),或者是否始终将其转换为同步请求?

    3 回复  |  直到 10 年前
        2
  •  28
  •   Dan Atkinson    10 年前
    HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(myUrl);
    //set up web request...
    ThreadPool.QueueUserWorkItem(o=>{ myRequest.GetResponse(); });
    

    也被称为失火和遗忘。

        3
  •  13
  •   Community CDub    7 年前

    (注:我开始将此作为评论输入,但随着我在研究中获得了一些额外的知识,它变得足够大,可以得到答案)

    1.线程池。队列用户工作项

    @ram提供的前两个链接以及@brian batchelders answer使用了有争议的threadpool.queueuserworkitem。在ASP.NET的上下文中,它是有争议的,因为未经拒绝的使用可能 让你的线程池挨饿 ,如@perhentian link 显示。

    2。异步调用

    然后我看了一下@ram's third link 它利用了begininvoke。从本质上讲,这似乎只是告诉一些代码 在另一个线程上运行 也是。所以这里没有决议。

    三。贝金特雷斯彭

    现在回到@perhentians 链接 . 它说明BeginGetResponse与实际线程有什么不同,因为它使用 IO完成端口(IOPC) . 因此,您实际上正在寻找的是一个仍然使用这些IOPC而不创建额外线程的解决方案。

    现在,为了了解.NET是如何做到这一点的,我试图深入研究httpwebrequest.BeginGetResponse,它实际上是一堆内部调用。它像:

    1. httpwebrequest.begingeresponse
    2. 服务点.提交请求
    3. 连接.提交请求
    4. 两种选择:
      • 如果连接已清除:connection.startrequest
      • 否则:connection.waitlist.add(请求)

    侍者名单

    首先,让我们考虑选项2:当连接完成之前的请求时,将处理所述等待列表。通过查看整个链中涉及的连接流,可以看到 线程池。队列用户工作项 备注如下:

    // 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???
    

    因此,至少在某些回退场景中,线程仍然可以通过使用begingeresponse,不经意间由框架生成!

    b.连接.startrequest

    现在,我们仍然有连接清晰的场景。回调由System.NET.Sockets.Socket.BeginConnect安装,并由BeginAccept实际调用。进一步挖掘会显示对ThreadPool.UnsafeRegisterWaitForSingleObject的调用,该对象的结果将用于等待。

    结论

    最后,我们可以知道在进行Begingeresponse时实际发生了什么:

    // 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);
    

    注意 超时。无限 .我仍在调查是否有可能让套接字运行一个不执行等待的代码路径,但就目前而言,这对我来说似乎是不可能的。

    我的结论是:似乎没有一种简单的方法可以在火灾和遗忘场景中使用iocps。因此,除非您可以让上面的套接字不等待BeginAccept完成,否则您将无法使用threadpool。