.net 与“一致”的词典;“昂贵的”;价值

.net 与“一致”的词典;“昂贵的”;价值,.net,multithreading,performance,concurrency,concurrentdictionary,.net,Multithreading,Performance,Concurrency,Concurrentdictionary,我有一个实现async方法的多线程应用程序。应用程序通过RabbitMq进行通信,有时需要在IModel上执行代价高昂的操作(BasicConsume)。我有一个ConcurrentDictionary,其中保存了IModel(key)和IBasicConsumer(value),以避免与MessageBroker的额外往返 在启动时,多个执行会到达代码的同一部分,在该部分中查找使用者(值)是否存在。在前40种情况下,答案是否定的,但我不想做40BasicConsume,根据提供的IModel(

我有一个实现
async
方法的多线程应用程序。应用程序通过RabbitMq进行通信,有时需要在
IModel
上执行代价高昂的操作(
BasicConsume
)。我有一个ConcurrentDictionary,其中保存了
IModel
(key)和
IBasicConsumer
(value),以避免与MessageBroker的额外往返

在启动时,多个执行会到达代码的同一部分,在该部分中查找使用者(值)是否存在。在前40种情况下,答案是否定的,但我不想做40
BasicConsume
,根据提供的
IModel
(键)只做一个或两个

使用
lock
语句会导致不可接受的性能损失

目前,我正在解决以下问题

var consumerTcs = new TaskCompletionSouce<IBasicConsumer>();
if (_consumerDictionary.TryAdd(channel, consumerTcs))
{
    var newConsumer = new EventingBasicConsumer(channel);
    newConsumer.Model.BasicConsume(queue, false, newConsumer)
    consumerTcs.TrySetResult(newConsumer);
    return consumerTcs.Task;
}
else
{
    return _consumerDictionary[channel].Task;
}
var consumerTcs=new TaskCompletionSouce();
if(_consumerDictionary.TryAdd(频道,consumerrtcs))
{
var newConsumer=新事件基本消费者(频道);
newConsumer.Model.BasicConsume(队列,false,newConsumer)
consumerTcs.TrySetResult(新消费者);
返回consumerTcs.Task;
}
其他的
{
返回_consumerDictionary[channel]。任务;
}
就是

  • 使用
    TaskCompletionSource
    (非expencive)作为字典的值
  • 使用
    TryAdd
    ,如果成功,则执行昂贵的操作
  • 如果不成功,则假定密钥存在,并返回
    TaskCompletionSource.Task

  • 然而,我仍然创建了我不使用的
    TaskCompletionSources
    ,这让我觉得有点难看。有什么建议可以帮助我解决这个问题,而不必使用
    ,也不必在创建未使用的对象时浪费时钟周期?

    您是如何衡量这个不可接受的性能影响的?另外,这也是
    GetOrAdd(TKey,Func)
    的目的,使用它而不是
    TryAdd
    和可能的争用条件,即如果您从字典中删除值,
    TryAdd
    可能返回
    false
    ,但获取该值可能会通过使用嵌套任务运行代码抛出
    KeyNotFoundException
    @acelent测量性能(20倍外部和50'000x内部)使用秒表。但是,
    GetOrAdd
    可能就是我要找的!谢谢!
    GetOrAdd
    不工作,因为将调用
    valueFactory
    ,直到
    valueFactory
    返回其值。这会导致多个不必要的消息代理往返。您可以使用
    GetOrAdd
    (使用
    Func
    )为了避免创建许多
    TaskCompletionSouce
    。它只不过是一个
    TryGet
    ,在没有值时可选地后跟一个
    TryAdd
    ,本质上是颠倒您当前的逻辑。如果有很多争用,最初可能会创建一些不必要的,但唯一能创建一个的方法是使用锁定块。唉,使用
    GetOrAdd
    ,除非设置捕获的变量,否则无法直接知道返回的对象是否是您创建的对象,因此手动
    TryGet
    ->
    TryAdd
    更简单,并且执行相同的工作。