架构深渊

慢慢走进程序的深渊……关注领域驱动设计、测试驱动开发、设计模式、企业应用架构模式……积累技术细节,以设计架构为宗。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Lucene.Net 多线程操作建议

Posted on 2008-11-21 21:50  chen eric  阅读(348)  评论(0编辑  收藏  举报

 

关键字: 并发

对于并发,Lucene.Net 遵循以下规则:

1. 允许任意多的读操作并发,即任意数量用户可同时对同一索引做检索操作。
2. 即便正在进行索引修改操作(索引优化、添加文档、删除文档),依然允许任意多的检索操作并发执行。
3. 不允许并发修改操作,也就是说同一时间只允许一个索引修改操作。

Lucene.Net 内部已经对多线程安全进行了处理,打开 IndexWrite.cs / IndexReade.csr 文件,会发现很多操作都使用了 lock 进行多线程同步锁定。只要遵循一定的规则,就可以在多线程环境下安全运行 Lucene.Net。

建议:

1. Directotry、Analyzer 都是多线程安全类型,只需建立一个 Singleton 对象即可。
2. 所有线程使用同一个 IndexModifier 对象进行索引修改操作。
3. IndexWriter/IndexReader/IndexModifier/IndexSearcher 最好使用同一个 Directory 对象,否则多线程并发读写时可能引发 FileNotFoundException。

IndexModifier 对象封装了 IndexWriter 和 IndexReader 的常用操作,其内部实现了多线程同步锁定。使用 IndexModifier 可避免同时使用 IndexWriter 和 IndexReader 时需要在多个对象之间进行同步的麻烦。等所有修改操作完成后,记住调用 Close() 方法关闭相关资源。并不是每次操作都需要调用 Optimize(),可以依据特定情况,定期执行优化操作。

--------

以下演示代码简单封装了一个 IndexModifier Signleton 类型,确保多线程使用同一个对象,且只能由最后一个多线程调用 Close 方法关闭。
代码不完善,仅供参考!需要做些修改才能应用于实际项目。

public class MyIndexModifier
{
  private static Directory directory = new RAMDirectory();
  private static Analyzer analyzer = new StandardAnalyzer();
  private static IndexModifier modifier;
  private static List<Thread> threadList = new List<Thread>();
  
  private MyIndexModifier() { }

  public static IndexModifier GetInstance()
  {
    lock (threadList)
    {
      if (modifier == null)
      {
        modifier = new IndexModifier(directory, analyzer, false);
        modifier.SetMaxFieldLength(1000);
      }

      if (!threadList.Contains(Thread.CurrentThread))
        threadList.Add(Thread.CurrentThread);

      return modifier;
    }
  }

  public static void Close()
  {
    lock (threadList)
    {
      if (threadList.Contains(Thread.CurrentThread))
        threadList.Remove(Thread.CurrentThread);

      if (threadList.Count == 0)
      {
        if (modifier != null)
        {
          modifier.Close();
          modifier = null;
        }
      }
    }
  }
}


多线程测试代码

for (int i = 0; i < 100; i++)
{
  new Thread(delegate()
  {
    IndexModifier writer = MyIndexModifier.GetInstance();

    for (int x = 0; x < 10; x++)
    {
      Document doc = new Document();
      doc.Add(Field.Text("a", "Hello, World!"));
      writer.AddDocument(doc);
    }

    Console.WriteLine("{0}: {1}", Thread.CurrentThread.ManagedThreadId, writer.DocCount());
    MyIndexModifier.Close(); // 注意不是调用 IndexModifier.Close() !

  }).Start();
}