【问题标题】:Does ManualResetEventSlim signaling degrades performance?ManualResetEventSlim 信号是否会降低性能?
【发布时间】:2020-04-28 10:58:16
【问题描述】:

我正在使用 ManualResetEventSlim 在我的应用程序中使用信号机制,如果请求/秒为 100,它会很好。随着我增加请求/秒,它会变得更糟。

例子:

100 请求/秒 -> 90% 的事务在 250 毫秒内完成,吞吐量(成功请求/秒)为 134。

150 请求/秒 -> 90% 的事务在 34067 毫秒内完成,吞吐量(成功请求/秒)为 2.2。

我使用 ConcurrentDictionary 如下:

// <key, (responseString,ManualResetEventSlim) >
private static ConcurrentDictionary<string, (string, ManualResetEventSlim)> EventsDict = new ConcurrentDictionary<string, (string, ManualResetEventSlim)>();

下面给出的过程描述了对 ManualResetEventSlim 的需求(Api 解决方案 1Api 解决方案 2 完全:

  1. Api 解决方案 1 (REST Api) 收到请求,它在 ConcurrentDictionary 中针对 key 添加一个元素(null,ManualResetEventSlim)并调用第三方服务( SOAP)使用异步/等待。第三方soap api返回确认响应,但实际响应待定。得到确认响应后,进入ManualResetEventSlim.wait

  2. 一旦第三方处理了请求,它就会使用公开的方法调用 Api 解决方案 2 (SOAP) 并发送实际响应。 Api 解决方案 2 通过发出 http 请求向 Api 解决方案 1 (REST Api) 发送响应,然后将数据插入数据库以进行审计日志。

  3. Api Solution 1将从响应字符串中获取key并更新ConcurrentDictionary中的响应字符串并设置信号。

  4. Api 解决方案 1 在向客户端返回响应之前释放 ManualResetEventSlim 对象。

【问题讨论】:

  • 只要 Solution2 工作,您就会阻塞 Solution1 的线程。您是否考虑过使用基于任务的异步(“async/await”)?
  • 是的,它是一个肥皂服务,我使用 async/await 但它总是返回两个响应。解决方案 2 是一个第三方服务,它会立即为每个请求返回确认响应,并且它要求在单独的公开方法上发送实际响应。我需要阻止请求,直到我得到实际响应
  • "当等待时间预计非常短,并且事件不跨越进程边界时,您可以使用ManualResetEventSlim获得比ManualResetEvent更好的性能b>" - docs.microsoft.com/en-us/dotnet/api/…
  • 您能否详细说明解决方案 2 发出的信号是如何工作的?当可以获取结果时如何得到通知?那是回调吗?一个事件?还有什么?
  • @PeterCsala 我已经在使用 ManualResetEventSlim

标签: c# multithreading asp.net-core signals event-wait-handle


【解决方案1】:

我认为,您应该能够通过将(string, ManualResetEventSlim) 替换为TaskCompletionSource&lt;string&gt; 来摆脱阻塞代码:

在解决方案 1 中,您可以这样做:

TaskCompletionSource<string> tcs = new TaskCompletionSource<string>()
EventsDict.AddOrUpdate( key, tcs );
await KickOffSolution2ThirdParty( /*...*/ );
string result = await tcs.Task; // <-- now not blocking any thread anymore

而对方:

void CallbackFromSolution2( string key, string result )
{
     if( EventsDict.TryRemove(key, out TaskCompletionSource<string> tcs )
     {
         tcs.SetResult(result);
     }
}

这当然只是这个想法的粗略轮廓。但希望足以让我的思路可以理解。我现在无法对此进行测试,因此欢迎任何改进/更正。

【讨论】:

  • 谢谢,我从上面的代码中得到了这个想法,它工作得很好。
猜你喜欢
  • 2011-12-25
  • 2013-05-22
  • 2016-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-01
相关资源
最近更新 更多