Task异步编程笔记

最近在做一个一维码扫码的功能,流程是打开设备端口→开启寻卡→循环读取扫码数据

寻卡就是打开扫码探头,循环读无非就是如果探头读取到数据就返回给我程序,但是程序不可能一直等着探头将数据返回,所以必须用异步方式。

之前也用过Task,但是用的比较少,这一次正好有这种需求,自己索性记录下。

下面是我最初的读卡方法

   public async Task<string> ReadYwm(int re)
        {
            byte[] reps = new byte[256];
            while (re == -16)
            {
                re = DriveApi.PICC_Reader_Card(CurrentHandller, reps);
            }
            
            char[] chars = new char[reps[1]];
            for (int i = 2; i < re; i++)
            {
                this.richTextBox1.Text += reps[i].ToString() + ",";
                chars[i - 2] = (char)reps[i];
            }
            string s = new string(chars);
            return s;
        }

 然后我是在一个点击事件里面去调用的,点击事件Winfrom默认是同步方法,当时我就新建了一个异步方法专门用来调用ReadYwm函数,代码如下:

      public async void Ywmxk()
        {
            try
            {
                StringBuilder req = new StringBuilder(4);
                req.Append("USB1");
                this.CurrentHandller = DriveApi.ICC_Reader_Open(req);
                if (this.CurrentHandller < 0)
                {
                    throw new Exception("句柄打开失败了!");
                }
                this.richTextBox1.Text = "句柄已打开,句柄值:" + CurrentHandller.ToString();
                byte[] reps = new byte[256];
                int re = DriveApi.PICC_Reader_xunka(CurrentHandller, 0, 16, reps);

                this.richTextBox1.Text = "寻卡调用完毕,寻卡返回,re:" + re.ToString() + "reps长度:" + reps.Length + "\r";

                string s = await ReadYwm(re);                
                this.richTextBox1.Text += "卡号:" + s + "\r";
            }
            catch (Exception ea)
            {
                this.richTextBox1.Text = "读取接触异常!" + ea.Message + "\r";
            }
            finally
            {
                if (CurrentHandller > 0)
                    DriveApi.ICC_Reader_Close(CurrentHandller);
            }
        }

后面调试发现还是同步的,原因是因为有awit ReadYwm,awit必须等待ReadYwm函数执行完毕。。。。所以上面的代码其实和同步代码一样。。。

调整下,写了个测试代码,直接用Task省略掉async 和awit,并通过ContinueWith实现任务回调。 直接看例子:

   public string testAsync(int i)
        {
            this.BeginInvoke(new Action(() => this.richTextBox1.Text += "进入testAsync方法\r"));
            Thread.Sleep(10000);
            return "hahahah";
        }

上面这个函数,在执行时候会有10秒的延迟,用来测试时候辨别用,可以把这个相当于上面的读卡函数,现在还缺一个调用的外部方法,下面代码提供:

   public void Test()
        {
            try
            {
                this.richTextBox1.Text = "进入同步测试方法\r";
                int i = 1;
                Task<string> t = Task.Factory.StartNew<string>((object val) =>
                   testAsync((int)val), i);
                t.ContinueWith(new Action<Task<string>>((y) =>
               {
                   this.BeginInvoke(new Action(() => { this.richTextBox1.Text += "异步返回值为:" + y.Result; }));
               }));
                this.richTextBox1.Text += "测试完毕\r";
            }
            catch (Exception ea)
            {
                this.richTextBox1.Text = ea.Message;
            }
        }

 在这里直接用Task.Factory.StartNew,Factory内部会启用一个后台线程,并且异步执行,我用一个Task<string>变量接收,并通过ContinueWith定义回调函数,这个回调函数

的入参就是t这个变量,所以在回调方法里直接y.Result可以输出testAsync的返回值; 我把ContinueWith称为回调函数,可能不太严谨吧,但是在我理解看来它的作用就是和回调函数一样,

一定是在task执行完毕后才会执行的。

下图就是执行的结果

 

上面的代码我没加图片上的时间,我是后面截图时候想为了让别人看到效果才临时补上的,其他代码没变。。。

这么看来,以后写异步和多线程的相关工作可以直接用Task来做了,不需要写Thread、BeginInvoke等等传统方式啦,瞬间感觉轻松多了

 

posted @ 2017-03-30 14:46  长沙大鹏  阅读(215)  评论(0编辑  收藏  举报