异步函数示例

我们增加一个名为"Task"的函数,代码为:

Dim Sum As Integer
For
i As Integer = 1 To 10
   
Sleep(20) '暂停线程20毫秒,模拟需要耗时的任务.
    Sum = Sum +
i

Next
Return
Sum

提示: Sleep是新增加的一个方法,用于暂停当前线程,这里用于模拟需要耗时的任务。

上述函数执行一次需要时间200毫秒(10 * 20),我们在命令窗口按顺序执行此函数50次:

Dim dt As Date = Date.Now
For
i As Integer = 1 To 50
    Functions.Execute("Task")

Next
Dim
tp As TimeSpan = Date.Now - dt
Output
.Show(tp.TotalSeconds) '显示总的耗时

用时大概10秒多一点,和实际计算的时间相符(50 * 200 = 10000毫秒),在这10秒时间内,你无法执行任何操作,单击菜单或表格,都不会有响应。

我们修改一下代码,用AsyncExecute代替Execute:

Dim dt As Date = Date.Now
For
i As Integer = 1 To 50
    Functions.AsyncExecute("Task")

Next
Dim
tp As TimeSpan = Date.Now - dt
Output
.Show(tp.TotalSeconds) '显示总的耗时

由于改用了AsyncExecute调用,所以函数Task成为了异步函数

你猜猜用时是多少? 10秒?1秒?0.1秒? 还是更少呢?

以上答案都不对,实际上用时是0秒,并不是说执行50次函数不需要时间,而是这里采用了异步执行方式,每个函数都在独立的线程中运行,不会阻塞主线程,不会导致程序无响应,这就是异步执行的好处。

我们将这种采用异步方式执行的函数,称为异步函数; AsyncExecute方法并不会返回函数的执行结果,这是可以理解的,因为AsyncExecute开启一个新的线程来执行函数后,会立即返回主线程,并不会等函数执行完毕,自然无法获取函数的执行结果。

如何获取异步函数的执行结果呢,我们在下一节讲述。

异步函数的问题

首先我们在全局代码中定义一个Public变量:

Public Total As Integer

关于Public变量,参考:Public变量

首先增加一个名为"AddTotal"的函数,代码为:

For i As Integer = 1 To 100
   
Total = Total + 1
Next

然后在命令窗口用AsyncExecute方法异步执行此函数100次:

Total = 0
For
i As Integer = 1 To 100
   
Functions.AsyncExecute("AddTotal")
Next

Sleep
(2000) '等待2秒,待所有子线程线程执行完毕
Return
Total

你可能认为Total的最终结果是10000,可反复测试后你会发现,Total只会接近10000,而且每次执行结果都会不同。
如果你不相信,认为只是一些子线程没有执行完毕而已,那么你可以将Sleep的参数增大,延长等待时间,你会发现Total的值确实不会 等于10000。

为什么会这样? 因为主线程用AsyncExecute方法异步执行AddTotal函数100次,等于开启了100个子线程同时执行AddTotal方法;假定某个时刻Total的值为99,此时A线程取Total的值得到99,准备加1,并将结果保存回Total变量,假定A线程在将结果保存 回Total变量之前,另一个线程也取Total变量的值,也得到99,同样加1后保存回Total变量,这样两个线程执行完毕之后,Total的值是100,而不是我们期望的101。这里只是结果不正确而已,如果你采用 var变量代替public变量,那么不仅仅是结果不正确的问题,程序可能会直接崩溃。

要解决这个问题,必须单独定义一个同步函数用于累加异步函数结果,这是下一节要讲述的内容。

 

 

 

 


本页地址:http://www.foxtable.com/mobilehelp/topics/3269.htm