0

我编写了一个 C# 库,它有一种方法可以从并行的多个文本段落中计算单词。文本段落以字符流的形式给出,每次getnextchar()调用都有随机延迟。我的库方法必须采用这些字符流的数组并返回组合的词频计数。为此,我有一个安全共享的词频数据结构和一个线程来读取每个字符流并更新共享集合。当所有线程都完成后,我将数据结构返回给客户端应用程序。

客户端应用程序需要每 10 秒一次的组合字数统计的中间结果。为此,我使用委托每 10 秒回调一次客户端的结果,直到所有工作线程都完成,然后我将最终结果返回给客户端。

我的问题是,当我用中间结果回调客户端时,我必须锁定我的共享数据结构并等待客户端应用程序从回调中返回,然后才能解锁它。在执行回调时,所有工作线程都被阻塞,等待数据结构上的锁。这似乎不是一件明智的事情,因为我认为我不应该依赖或相信客户端代码会立即返回,甚至根本不应该返回。然而,他们唯一能想到的不依赖于客户端代码的其他方式是制作我的数据结构的副本或快照,并通过回调将其传递给客户端。这是以内存和计算为代价的,但是一旦复制完成,工作人员可以继续更新共享集合,回调可以做任何它想做的事情。

我的问题有两个:

1)这是两个弊端中较小的一个,允许错误的客户端回调实现阻止工作人员,或定期执行昂贵的操作。

2)有没有办法解决以上任何一个都不能解决的问题?

4

2 回答 2

2

我肯定会说两个弊端中较大的一个是信任客户。在持有锁的同时回调未知代码会导致死锁和更糟糕的情况。是的,您将支付开销来拍摄您的结构的快照并将其归还。但是快照的额外内存超过了在持有锁时调用的风险。

我遇到过类似的情况,到目前为止,快照还不是问题。如果是这样,您可以找到几种解决此问题的方法。包括增加调用客户端的频率,这将减少在给定时间必须快照的数据量。

解决此问题的另一种方法是使用不可变的数据结构。当您准备好与客户交谈时,只需中断当前版本并将其交给客户即可。允许您的后台线程开始构建一个新线程。

于 2009-06-14T02:26:26.387 回答
0

我最近在编写库时遇到了这样的问题——它并不完全相同,但基本问题是相同的——你能在多大程度上信任使用你的库的客户。如果你可以依赖客户端做某件事,当你可以得到更好的性能时,你会怎么做?

我们最终做的是有两个代码路径和一个客户端可以在我们的对象上设置的标志,以指示采用哪条路径。本质上,这是一面“你可以相信我”的旗帜。如果没有设置(默认),库会假设它正在处理一个它不能信任的客户端,并且永远不会给客户端一个对内部数据结构的直接引用——它总是有一个副本。但是,如果客户端设置了该标志,那么他们将可以直接访问真实结构,并且他们必须遵循我们制定的规则(在标志和访问器上都有记录)。

但是,就您的情况(事件)而言,听起来您还有另一种选择-两个不同的事件。“正常”的一种(在将结构提供给客户端之前克隆结构),以及持有锁并为其提供要检查的真实结构的“高级”。只需确保清楚记录,如果您使用高级引用,则只能在事件处理程序期间使用该引用,并且最好快速,因为您在这样做时会暂停处理。

于 2009-06-14T02:25:45.640 回答