2

我的 C# 应用程序中有一个共享资源(文本处理器类)的静态集合,它们响应关键字。每个处理器都是有状态的,因此不能在多线程上下文中工作。我正在寻找一种组织这些的好方法,以便我可以对它们进行线程安全访问。

例如,我可以在每个处理器中嵌入一个同步对象

public abstract class TextProcessor
{
    protected internal readonly object sync = new object();

    public abstract void Run( string text );
}

public class DocumentProcessor
{
    private static Dictionary<string,TextProcessor> s_procMap = ...;

    public void Run( string [] words1, string[] words2 )
    {
        ThreadPool.QueueUserWorkItem( Process, words1 );
        ThreadPool.QueueUserWorkItem( Process, words2 );
    }

    private void Process( object arg )
    {
        foreach( var word in words )
        {
            var proc = s_processor[word];
            lock( proc.sync )
            {
                proc.Run( word );
            }
        }
    }

假设我不能将我的处理器重写为无状态(这是一种选择,但由于重构量很大,这是最后的手段),有没有更好的方法来表达这一点?

4

2 回答 2

2

当前方法的问题是单个忙TextProcessor可以停止剩余单词的处理。如果您改为给每个TextProcessor单词一个(线程安全的)队列,那么您可以在不阻塞的情况下将工作排入队列并让TextProcessor出队并按顺序处理单词。

查看TPL 数据流ActionBlock库。它处理排队,处理的开始以及最终关闭,以防没有更多的工作。TaskTask

请注意,当没有工作排队时,没有线程被阻塞。这是一个重要的可扩展性属性。

于 2013-10-07T12:20:34.323 回答
1

如果你真的不想改变处理器......那么我会做一个包装器。

public class ProcWrapper
{
  private TextProcessor _proc;
  private ActionBlock<string> _actBlock;

  public ProcWrapper(TextProcessor proc)
  {
    _proc = proc;

    _actBlock = new ActionBlock<string[]>(word=>
    {
      _proc.Run(word);
    });
  }

  public void AddWord(string words)
  {
    _actBlock.Post(word);
  }

  public void WaitForCompletion()
  {
    _actBlock.Completion.Wait();
  }
}

并像以前一样使用它:

Dictionary<string,ProcWrapper> s_procMap = ...;

void Run( string [] words )
{
  // NOTE: This assumes the same thread will access s_procMap.
  foreach(var word in words)
    s_procMap[word].AddWord(word);
}

我认为这与您正在寻找的内容很接近。

查看http://msdn.microsoft.com/en-us/library/hh228603.aspx了解更多信息DataFlowhttpTPL : //msdn.microsoft.com/en-us/library/hh194684.aspx了解更多信息具体到.ActionBlock<T>

于 2013-10-07T15:56:53.010 回答