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等等传统方式啦,瞬间感觉轻松多了