.NET異步和多線程系列(五)- 多線程雙色球項目

本文是.NET異步和多線程系列的第五章,本章將綜合以前分享的異步和多線程來實現簡單的雙色球項目。html

話很少說,下面咱們直接進入本章主題。多線程

首先咱們來看下需求分析:dom

  雙色球:投注號碼由6個紅色球號碼和1個藍色球號碼組成。異步

  紅色球號碼:從01--33中選擇,不重複。ui

  藍色球號碼:從01--16中選擇。this

  球號碼隨機的規則:遠程獲取一個隨機數據,這個會有較長的時間損耗。spa

雙色球項目界面設計以下:線程

接下來咱們重點來看下代碼:設計

模擬獲取遠程隨機數:code

using System;
using System.Threading;

namespace MyLottery.Common
{
    /// <summary>
    /// 解決隨機數重複問題
    /// 同時模擬遠程請求的隨機延時
    /// </summary>
    public class RandomHelper
    {
        /// <summary>
        /// 隨機獲取數字並等待一段時間
        /// </summary>
        public int GetRandomNumberDelay(int min, int max)
        {
            Thread.Sleep(this.GetRandomNumber(500, 1000)); //隨機休息一下
            return this.GetRandomNumber(min, max);
        }

        /// <summary>
        /// 獲取隨機數(解決重複問題)
        /// </summary>
        public int GetRandomNumber(int min, int max)
        {
            Guid guid = Guid.NewGuid(); //每次都是全新的ID
            string sGuid = guid.ToString();
            int seed = DateTime.Now.Millisecond;
            for (int i = 0; i < sGuid.Length; i++)
            {
                switch (sGuid[i])
                {
                    case 'a':
                    case 'b':
                    case 'c':
                    case 'd':
                    case 'e':
                    case 'f':
                    case 'g':
                        seed = seed + 1;
                        break;
                    case 'h':
                    case 'i':
                    case 'j':
                    case 'k':
                    case 'l':
                    case 'm':
                    case 'n':
                        seed = seed + 2;
                        break;
                    case 'o':
                    case 'p':
                    case 'q':
                    case 'r':
                    case 's':
                    case 't':
                        seed = seed + 3;
                        break;
                    case 'u':
                    case 'v':
                    case 'w':
                    case 'x':
                    case 'y':
                    case 'z':
                        seed = seed + 3;
                        break;
                    default:
                        seed = seed + 4;
                        break;
                }
            }

            Random random = new Random(seed);
            return random.Next(min, max);
        }
    }
}

界面核心代碼以下:

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

using MyLottery.Common;

namespace MyLottery
{
    /// <summary>
    /// 多線程雙色球項目
    /// 需求:
    ///     雙色球:投注號碼由6個紅色球號碼和1個藍色球號碼組成。
    ///     紅色球號碼:從01--33中選擇,不重複。
    ///     藍色球號碼:從01--16中選擇。
    /// 
    /// 球號碼隨機的規則:遠程獲取一個隨機數據,這個會有較長的時間損耗。
    /// </summary>
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.btnStart.Enabled = true;
            this.btnStop.Enabled = false;
        }

        #region 字段和屬性

        #region 數據 

        /// <summary>
        /// 紅球集合  其實能夠寫入配置文件
        /// </summary>
        public string[] _redNums =
        {
            "01","02","03","04","05","06","07","08","09","10",
            "11","12","13","14","15","16","17","18","19","20",
            "21","22","23","24","25","26","27","28","29","30",
            "31","32","33"
        };

        /// <summary>
        /// 藍球集合
        /// </summary>
        private string[] _blueNums =
        {
            "01","02","03","04","05","06","07","08","09","10",
            "11","12","13","14","15","16"
        };

        #endregion 數據

        private bool _isGoOn = true;
        private List<Task> _taskList = new List<Task>();
        private static readonly object _lockObj = new object();

        #endregion 字段和屬性

        /// <summary>
        /// 點擊開始
        /// </summary>
        private void btnStart_Click(object sender, EventArgs e)
        {
            try
            {
                #region 初始化動做

                this.btnStart.Text = "運行ing";
                this.btnStart.Enabled = false;
                this._isGoOn = true;
                this._taskList = new List<Task>();
                this.lblBlue.Text = "00";
                this.lblRed1.Text = "00";
                this.lblRed2.Text = "00";
                this.lblRed3.Text = "00";
                this.lblRed4.Text = "00";
                this.lblRed5.Text = "00";
                this.lblRed6.Text = "00";

                #endregion 初始化動做

                Thread.Sleep(1000);
                foreach (var control in this.gboSSQ.Controls)
                {
                    if (control is Label)
                    {
                        Label label = (Label)control;
                        if (label.Name.Contains("Blue"))
                        {
                            _taskList.Add(Task.Run(() =>
                            {
                                try
                                {
                                    while (_isGoOn)
                                    {
                                        //一、獲取隨機數 
                                        int index = new RandomHelper().GetRandomNumberDelay(0, 16);
                                        string sNumber = this._blueNums[index];

                                        //二、更新界面
                                        //this.lblBlue.Text = sNumber;
                                        //子線程不能操做控件,委託給主線程操做
                                        //this.Invoke
                                        this.Invoke(new Action(() =>
                                        {
                                            label.Text = sNumber;
                                        }));

                                        //三、循環
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Console.WriteLine(ex.ToString());
                                }
                            }));
                        }
                        else if (label.Name.Contains("Red"))
                        {
                            _taskList.Add(Task.Run(() =>
                            {
                                try
                                {
                                    while (_isGoOn)
                                    {
                                        int index = new RandomHelper().GetRandomNumberDelay(0, 33);
                                        string sNumber = this._redNums[index];
                                        //可能重複  得去重
                                        //檢測下是否重複,直接比對界面
                                        //獲取隨機   比對界面   更新
                                        lock (_lockObj)
                                        {
                                            List<string> usedNumberList = this.GetUsedRedNumbers();
                                            if (!usedNumberList.Contains(sNumber))
                                            {
                                                this.Invoke(new Action(() =>
                                                {
                                                    //Thread.Sleep(10);
                                                    label.Text = sNumber; //委託給主線程操做
                                                })); //其實是同步的
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Console.WriteLine(ex.Message);
                                }
                            }));
                        }
                    }
                }

                Task.Factory.ContinueWhenAll(this._taskList.ToArray(), tArray =>
                {
                    this.ShowResult();
                    this.Invoke(new Action(() =>
                    {
                        this.btnStart.Enabled = true;
                        this.btnStop.Enabled = false;
                    }));
                });

                Task.Delay(10 * 1000).ContinueWith(t =>
                {
                    this.Invoke(new Action(() =>
                    {
                        this.btnStop.Enabled = true;
                    }));
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine("雙色球啓動出現異常:{0}", ex.ToString());
            }
        }

        /// <summary>
        /// 點擊結束
        /// </summary>
        private void btnStop_Click(object sender, EventArgs e)
        {
            this._isGoOn = false;

            #region 死鎖

            //此處主線程不能直接WaitAll 界面會卡死 死鎖了
            //主線程要等着子線程完成後才能往下走,而子線程又要等着主線程幫忙幹件過後才能往下走,二者都在等着對方,這就致使了死鎖。
            //{
            //    Task.WaitAll(this._taskList.ToArray());
            //    this.ShowResult();
            //}

            #endregion 死鎖

            #region ShowResult這事情在這裏作不合適,應該放到回調裏面去作比較合適

            //此處要等子線程完成的話應該再開一個子線程去等纔對
            //{
            //    Task.Run(() =>
            //    {
            //        Task.WaitAll(this._taskList.ToArray());
            //        this.ShowResult();
            //    });
            //}

            #endregion ShowResult這事情在這裏作不合適,應該放到回調裏面去作比較合適
        }

        #region 公共方法

        /// <summary>
        /// 獲取已經使用過的紅色數字
        /// </summary>
        private List<string> GetUsedRedNumbers()
        {
            List<string> usedNumberList = new List<string>();
            foreach (var controler in this.gboSSQ.Controls)
            {
                if (controler is Label)
                {
                    if (((Label)controler).Name.Contains("Red"))
                    {
                        usedNumberList.Add(((Label)controler).Text);
                    }
                }
            }
            return usedNumberList;
        }

        /// <summary>
        /// 彈框提示數據
        /// </summary>
        private void ShowResult()
        {
            MessageBox.Show(string.Format("本期雙色球結果爲:{0} {1} {2} {3} {4} {5}  藍球{6}"
                , this.lblRed1.Text
                , this.lblRed2.Text
                , this.lblRed3.Text
                , this.lblRed4.Text
                , this.lblRed5.Text
                , this.lblRed6.Text
                , this.lblBlue.Text));
        }

        #endregion 公共方法
    }
}

運行結果以下:

 

Demo源碼:

連接:https://pan.baidu.com/s/1J2OFDxI4dHspkrh9CJy2Sg 
提取碼:h2l3

此文由博主精心撰寫轉載請保留此原文連接:https://www.cnblogs.com/xyh9039/p/13616391.html

相關文章
相關標籤/搜索