加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 如何在不阻塞当前线程的情况下发布HTTP请求并等待回调?

发布时间:2020-12-15 05:41:17 所属栏目:百科 来源:网络整理
导读:我们有一个.NET应用程序,它使用基于HTTP的API,我们将请求发送到第三方HTTP端点(不在我们的控制之下),并且它稍后在我们提供的HTTP端点上调用我们;就像是: WebRequest request = WebRequest.Create(urlToMethod);request.Method = @"POST";request.Headers.Ad
我们有一个.NET应用程序,它使用基于HTTP的API,我们将请求发送到第三方HTTP端点(不在我们的控制之下),并且它稍后在我们提供的HTTP端点上调用我们;就像是:
WebRequest request = WebRequest.Create(urlToMethod);
request.Method = @"POST";
request.Headers.Add(@"Callback","http://ourserver?id="+id );

我们成千上万的这些调用,所以我们希望尽可能有效(在速度/内存/线程等方面)

就回调代码而言,我们有一个充当监听器的类型;这就是我们启动它的方式:

_httpListener = new HttpListener();
_httpListener.Prefixes.Add(ourServer);
_httpListener.Start();
_httpListener.BeginGetContext(callback,null);

当服务器回调我们时,它会点击我们的回调方法,如下所示:

HttpListenerContext context = _httpListener.EndGetContext(result);

HttpListenerResponse httpListenerResponse = context.Response;
httpListenerResponse.StatusCode = 200;
httpListenerResponse.ContentLength64 = _acknowledgementBytes.Length;

var output = httpListenerResponse.OutputStream;
output.Write(_acknowledgementBytes,_acknowledgementBytes.Length);

context.Response.Close();

var handler = ResponseReceived;

if (handler != null)
{
    handler(this,someData);
}

因此,我们有一个这个侦听器的实例(_which内部使用HttpListener),并且对于它获得的每个响应,它都会通知ResponseReceived事件的所有订阅者.

订阅者(可能是数百个)只关心与其特定id相关联的数据.订阅者看起来像:

_matchingResponseReceived = new ManualResetEventSlim(false);
_listener.WhenResponseReceived += checkTheIdOfWhatWeGetAndSetTheEventIfItMatches;
postTheMessage();
_matchingResponseReceived.Wait(someTimeout);

这是困扰我的最后一行.我们发布消息,然后阻止整个线程等待Listener获得响应并调用我们的事件处理程序.我们想使用任务,但如果我们阻止整个线程等待回调,它似乎不会给我们太多.

是否有更好的(更多TPL友好)方式实现这一点,以便没有线程被阻止,我们同时触发更多的请求?

解决方法

异步 – 等待与TaskCompletionSource一起为此做了很多.

发送方创建TaskCompletionSource,将其添加到字典中(键是请求的id),发出请求并返回TaskCompletionSource的Task.

接收器然后查看字典以找到正确的TaskCompletionSource,从那里删除它并设置其结果.

sender方法的调用者将等待返回的Task,它将异步等待接收者处理回调调用.

在代码中,它看起来像这样:

// TODO: this probably needs to be thread-safe
// you can use ConcurrentDictionary for that
Dictionary<int,TaskCompletionSource<Result>> requestTcses;

public async Task<Result> MakeApiRequestAsync()
{
   int id = …;
   var tcs = new TaskCompletionSource<Result>();
   requestTcses.Add(id,tcs);
   await SendRequestAsync(id);
   return await tcs.Task;
}

…

var result = await MakeApiRequest();
var context = await _httpListener.GetContext();

// parse the response into id and result

var tcs = requestTcses[id];
requestTcses.Remove(id);
tcs.SetResult(result);

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读