2010年11月7日 星期日

TPL 學習日記(8): BlockingCollection 的 GetConsumingEnumerable

上一回提到了 BlockingCollection,順便提一個值得玩玩的事。

BlockingCollection 實作了IProducerConsumerCollection<T>. 此 interface 定義了製造者/消費者使用方式的安全執行緒集合。而BlockingCollection 是其中最典型的實作。BlockingCollection 可以使用GetConsumingEnumerable 取得加入/移除到集合中的項目。如下範例。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Threading;

namespace TPL_1 {
  class Program {
    static void Main(string[] args) {
      var primes = new BlockingCollection<int>();
      var t = Task.Factory.StartNew(
        () =>
        {
          //取得對BlockingCollection中新增或移除的每個項目
          foreach (var item in primes.GetConsumingEnumerable())
            Console.WriteLine(item);
        });
      for (int i = 0; i < 5000000; i++)
        if (IsPrime(i)) primes.Add(i);
      primes.CompleteAdding(); //結束新增
      t.Wait(); //直到 t 執行完
    }

   
    /// <summary>
    /// 是否為質數
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    static bool IsPrime(int input) {
      int bound = (int)Math.Sqrt(input);
      for (int i = 2; i <= bound; i++)
      {
        if (input % i == 0) return false;
      }
      return true;
    }

    static TimeSpan Time(Action a) {
      Stopwatch w = Stopwatch.StartNew();
      a();
      return w.Elapsed;
    }
  }
}

執行起來,功能平凡無奇。好玩的是,這樣的技巧已經在之前的「讀取大型文字檔」中顯示過了,而GetConsumingEnumerable 以相同的方式實作出來。

CompleteAdding() 方法標示該集合不會再新增項目,因此 GetConsumingenumerable 的巡覽才會結束。

沒有留言:

Share with Facebook