zoukankan      html  css  js  c++  java
  • .NET异步和多线程系列(五)- 多线程双色球项目

    本文是.NET异步和多线程系列的第五章,本章将综合之前分享的异步和多线程来实现简单的双色球项目。

    话不多说,下面我们直接进入本章主题。

    首先我们来看下需求分析:

      双色球:投注号码由6个红色球号码和1个蓝色球号码组成。

      红色球号码:从01--33中选择,不重复。

      蓝色球号码:从01--16中选择。

      球号码随机的规则:远程获取一个随机数据,这个会有较长的时间损耗。

    双色球项目界面设计如下:

    接下来我们重点来看下代码:

    模拟获取远程随机数:

    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)
                                        {
                                            //1、获取随机数 
                                            int index = new RandomHelper().GetRandomNumberDelay(0, 16);
                                            string sNumber = this._blueNums[index];
    
                                            //2、更新界面
                                            //this.lblBlue.Text = sNumber;
                                            //子线程不能操作控件,委托给主线程操作
                                            //this.Invoke
                                            this.Invoke(new Action(() =>
                                            {
                                                label.Text = sNumber;
                                            }));
    
                                            //3、循环
                                        }
                                    }
                                    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

    版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!

  • 相关阅读:
    关于Class.getResource和ClassLoader.getResource的路径问题
    spring源码第一章_获取源码并将源码转为eclipse工程
    《ORACLE数据库管理与开发》第三章学习之常用函数记录
    hibernate部分源码解析and解决工作上关于hibernate的一个问题例子(包含oracle中新建表为何列名全转为大写且通过hibernate取数时如何不用再次遍历将列名(key)值转为小写)
    整合Spring时Service层为什么不做全局包扫描详解
    Tomcat启动时加载数据到缓存---web.xml中listener加载顺序(例如顺序:1、初始化spring容器,2、初始化线程池,3、加载业务代码,将数据库中数据加载到内存中)
    tomcat出现的PermGen Space问题
    org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/pcisv7]]
    用户线程和守护线程
    @override的意思
  • 原文地址:https://www.cnblogs.com/xyh9039/p/13616391.html
Copyright © 2011-2022 走看看