国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

C#實現生產者消費者隊列

2019-11-14 14:02:45
字體:
來源:轉載
供稿:網友

開發過程中經常會碰到這樣的場景:需要從一個地方獲取一些數據,然后處理數據并將其保存在數據庫中。

PRivate void FetchData() {}private void SaveData() {}static void Main(string[] args){    for (int i = 0; i < 10; i++)    {        FetchData();  // 獲取數據        SaveData();  // 處理并保存    }}

例如上述代碼例子這樣順序執行,執行會很慢,原因是獲取數據和處理并保存的過程都可能導致阻塞,然而FetchData()每次取數據并不需要等待上一條數據保存完成再進行。

這樣的場景非常適合用生產者消費者隊列:生產者就是FetchData(),用來生產數據;消費者SaveData(),用來消費數據。

舉個實際例子,我們需要通過一個Web Api獲取一些城市的天氣情況,并將其保存到數據庫中。

實現方式:

  1. 需要一個任務隊列,生產者可以向隊列中插入任務,消費者可以從任務隊列中取出任務來執行。
  2. 為保證線程安全,使用一個鎖來保護這個隊列的訪問。
  3. 制定一個退出策略,在所有任務完成時釋放資源。

下邊是實現的完整代碼:

class Program    {        // 任務隊列        static Queue<string> _tasks = new Queue<string>();                // 為保證線程安全,使用一個鎖來保護_task的訪問        readonly static object _locker = new object();                // 通過 _wh 給工作線程發信號        static EventWaitHandle _wh = new AutoResetEvent(false);        static Thread _worker;        static void Main(string[] args)        {            // 需要獲取天氣情況的城市對應代碼            var cityIds = new List<int> {101280601, 101010100, 101020100, 101110101, 101040100};                        // 任務開始,啟動工作線程            _worker = new Thread(Work);            _worker.Start();            // 生產者將數據插入隊里中,并給工作線程發信號            foreach (var cityId in cityIds)                EnqueueTask(FetchData(cityId));            // 任務結束            Dispose();          }        /// <summary>執行工作</summary>        static void Work()        {            while (true)            {                string work = null;                lock (_locker)                {                    if (_tasks.Count > 0)                    {                        work = _tasks.Dequeue(); // 有任務時,出列任務                                                if (work == null)  // 退出機制:當遇見一個null任務時,代表任務結束                            return;                    }                }                if (work != null)                    SaveData(work);  // 任務不為null時,處理并保存數據                else                    _wh.WaitOne();   // 沒有任務了,等待信號            }        }        /// <summary>插入任務</summary>        static void EnqueueTask(string task)        {            lock (_locker)                 _tasks.Enqueue(task);  // 向隊列中插入任務                         _wh.Set();  // 給工作線程發信號        }                /// <summary>結束釋放</summary>        static void Dispose()        {            EnqueueTask(null);      // 插入一個Null任務,通知工作線程退出            _worker.Join();         // 等待工作線程完成            _wh.Close();            // 釋放資源        }        /// <summary>獲取數據</summary>        static string FetchData(int cityId)        {            var wc = new WebClient { Encoding = Encoding.UTF8 };            var url = string.Format("http://www.weather.com.cn/adat/sk/{0}.html", cityId);            return wc.DownloadString(url);        }        /// <summary>處理保存</summary>        static void SaveData(string data)        {            var weatherInfo = (JsonConvert.DeserializeObject(data, typeof(Dictionary<string, Weatherinfo>)) as Dictionary<string, Weatherinfo>)["weatherinfo"];                        Console.WriteLine("[{0}]:{1} 氣溫({2}) 風向({3}) 風力({4})", weatherInfo.Time, weatherInfo.City, weatherInfo.Temp, weatherInfo.Wd, weatherInfo.Ws);                        Thread.Sleep(200);  // 模擬數據保存        }    }    public class Weatherinfo    {        public string City { get; set; }        public string Temp { get; set; }        public string Time { get; set; }        public string Wd { get; set; }        public string Ws { get; set; }    }}

 解釋:

  1. Main方法中,我們首先啟動了一個工作線程,由于此時隊列中沒有任務,因此工作線程在等待信號。
  2. 通過EnqueueTask向隊列中插入任務,并通過等待句柄_wh發信號給工作線程,工作線程收到信號后就開始執行處理保存。
  3. 當生產者獲取完所有數據時,插入null任務,并等待工作線程完成。工作線程最后執行到null任務時退出。

 

參考:Threading in C# --> 中文翻譯


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 灌云县| 行唐县| 泾阳县| 固阳县| 宜君县| 龙江县| 辉县市| 罗城| 固阳县| 象州县| 连城县| 建水县| 三明市| 西华县| 清远市| 柘城县| 西林县| 革吉县| 长沙市| 长丰县| 陵川县| 元谋县| 大厂| 万州区| 义乌市| 边坝县| 庆云县| 攀枝花市| 青州市| 武山县| 伊金霍洛旗| 古浪县| 同心县| 怀来县| 专栏| 岑溪市| 九台市| 中超| 平湖市| 芦山县| 定州市|