从多个线程持久增加数字列表的最快方法是什么?

时间:2014-07-31 18:02:07

标签: c# multithreading

我的应用程序有不同的任务,每个人都通过不同端点上的每个HTTP POST发布XML Document。对于每个线程,我需要记录我发送的消息的计数,该消息由唯一的增量编号标识。

我需要一种机制,在端点收到消息后会保存最后发送的消息ID,这样如果出现问题并且应用程序需要重新启动它将不再发送相同的消息,并且将从目前的位置重新启动。

如果我不坚持计数器,在我的笔记本电脑上,我可以设法获得每运行5个任务的每个队列每秒处理大约100条消息的吞吐量。我的目标是通过坚持计数器来实现吞吐量减少不超过10/15%。

使用SQL Server保存计数器,每个任务都有一行,这使我的吞吐量降低了50%。将计数器值保存在每个任务的文本文件上要快一点,但仍远离我的目标。我正在寻找一种方法来保持这些信息,以便我尽可能接近我的目标。我认为可能附加最后处理的Id而不是更新它可以帮助我避免可能的写锁定,但最重要的是我不在乎我是否为了性能而浪费磁盘空间或者更高读取最后一个计数器的启动时间。

根据您的经验,即使以更多磁盘空间为代价,可以快速避免争用并安全地保留多个任务中的数据?

1 个答案:

答案 0 :(得分:3)

通过ManagedEsent - PersistentDictionary包装器,您可以通过ESENT存储获得相当不错的性能。

PersistentDictionary类是并发的,并提供对ESENT后端的实际并发访问。您将以键值对格式表示所有内容。

试一试,编写的代码不多。

ESENT是一个进程内数据库引擎,基于磁盘的+内存中缓存,用于几个Windows组件(搜索,交换等)。它确实提供了事务支持,这就是您所追求的。

自2000年以来,所有版本的Windows中都包含 ,因此您无需安装除ManagedEsent之外的任何依赖项。

你可能想要定义这样的东西:

var dictionary = new PersistentDictionary<Guid, int>("ThreadStorage");

我认为,密钥应该是独特的(甚至可能是服务端点),以便您可以在重新启动后重新映射它。该值是最后一个消息标识符。

我正在以无耻的方式粘贴他们的表现基准:

  • 连续插入 32,000个条目/秒
  • 随机插入 17,000个条目/秒
  • 随机更新 36,000个条目/秒
  • 随机查找(数据库缓存在内存中) 137,000个条目/秒
  • Linq查询(记录范围) 14,000个查询/秒

您符合随机更新的情况,正如您所看到的那样,可以提供非常好的吞吐量。