执行异步函数

本节内容可参考示例文件"CaseStudy\异步函数.Table"。

为更好地支持WebViewer的混合开发模式,避免界面假死,提升用户体验,Foxtable在新版本中引入了基于Await的异步编程模型。

现在,只需通过一个简单的注释标记'''Async,即可轻松实现自定义函数的异步调用,让耗时操作不再阻塞您的应用,异步编程从此不再复杂。

重要
提示 :

1、Foxtable的异步编程是基于自定义函数的,有关自定义函数,请参考:自定义函数

2、高级开发指南中有关异步函数的介绍已经过时,今后请使用本节介绍的方式异步执行函数,要方便可靠很多。

异步执行

首先
增加一个自定义函数Sum,这个函数非常耗时,代码为:

Dim sum As Long
For
m As Integer = 1 To 10000
   
For i As Integer = 0 To 1000000
        sum = sum + i
   
Next
Next

Return
sum

然后在命令窗口测试这个函数:

Dim sum As Long = Functions.Execute("Sum")
Return
sum

我们要等待很久才能得到计算结果,且在等待的过程中,不能进行其他任何操作。

现在将测试代码改为:

'''Async
Dim sum As Long = Await Functions.ExecuteAsync("Sum")
Return
sum

这里有三处改变:

1、代码第一行加上了
注释标记'''Async告诉系统此代码段支持异步任务。

2、在函数调用的前面加上了Await关键词,用于等待异步任务完成并获取其结果。

3、调用函数的方法由
Execute改为ExecuteAsync(请不要和以前的AsyncExecute混淆了)

再次运行修改后的代码,您会发现虽然仍然需要等待很久才能得到计算结果,但在等待的过程中,Foxtable的界面不会卡死,您可以正常进行其他操作。这就是异步执行的魅力所在——它将耗时任务放到了后台运行,避免了阻塞主界面线程。

前面的3处改变,除了3是必须的,1和2都不是必须的,如果满足下述两个条件,则可以去掉1和2:

1、函数没有返回值,或者不需要获取函数返回值。

2、不需要等函数运行结束就执行后续代码。

例如我们定义一个异步函数msgSum, 这个函数没有返回值,代码为:

Dim sum As Long
For
m As Integer = 1 To 10000
   
For i As Integer = 0 To 1000000
        sum = sum + i
   
Next
Next

MessageBox.Show(
"执行完毕,结果:" & sum, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information)

命令窗口异步执行这个函数:

Functions.ExecuteAsync("msgSum")

过一段时间会提示计算结果,在等待 期间依然可以进行其他操作。


重要提示: 凡是用到Await关键词的代码,不管是命令窗口、自定义函数还是事件代码,第一行必须是注释标记:
'''Async

命名规范

我们需要遵守一个规范:凡是要异步执行的函数,后缀名都用"Async"。

现在我们新增一个函数,代码和Sum函数完全一样,名称为"SumAsync"。

尽管函数名是"Sum"也好,是"SumAsync"也好,都不会有任何影响,但是SumAsync能让后来者一眼看出:函数作者希望你异步执行这个函数。

现在命令窗口的测试代码为:

'''Async
Dim sum As Long = Await Functions.ExecuteAsync("SumAsync")
Return
sum

我们通过
ExecuteAsync和SumAsync,确保后来者一眼就能看出,这里在执行一个异步函数,当然通过Await也可以看出,但正如前面所言,Await不是必须的。

这个后来者大概率是你自己,所以规范一点可利人利己。


关于Await

Await用于等待异步函数运行结束并获得返回值(如果有的话)。

所以Await关键词并不是必须的,如果你不需要获得异步函数的返回值,或者异步函数根本没有返回值,且你希望不等异步函数结束就开始运行后面的代码,那么就可以去掉Await关键词 。

例如我们定义一个异步函数SubAsync,代码为:

'''Async
Await
System.Threading.Tasks.Task.Delay(5000) '暂停5秒,模拟高耗时操作

在命令窗口执行下面的代码:

Output.Show("开始执行:" & Date.Now)
Functions.ExecuteAsync(
"SubAsync")
Output.Show(
"执行结束:" & Date.Now)

可以看到输出的开始时间和结束时间是相同的,因为这里没有Await关键词,所以并没有等异步函数运行结束就输出了结束时间。

如果将代码改为:


'''Async
Output.Show(
"开始执行:" & Date.Now)
Await
Functions.ExecuteAsync("SubAsync")
Output.Show(
"执行结束:" & Date.Now)

则结束时间会比开始时间晚5秒,因为要等异步函数运行结束才输出结束时间,而异步函数消耗的时间为5秒。


但不管有没有Await关键词,只要你是用
ExecuteAsync方法执行函数,函数都是异步执行的,所以在等待的过程中, 界面都不会卡死,你可以继续进行其他操作。

使用异步函数

异步函数最终是为同步代码服务的。

异步函数可以在命令窗口执行,也可以直接用在所有事件代码中,不需要特别的处理,只需记得需要Await的时候,代码的第一行必须是注释标记:
'''Async

我们可以用个小例子来测试一下(本示例文件的窗口"异步函数"):

新建一个窗口,插入一个Button和一个TextBox,前者用于执行异步函数,后者用于显示计算结果。

Button按钮的代码设置为:

'''Async
e.Sender.Enabled = False
e.Sender.Text =
"正在计算,请稍候..."
Dim
result As Long = Await Functions.ExecuteAsync("SumAsync")
e.Form.Controls(
"TextBox1").Value = result
e.Sender.Text =
"开始计算"
e.Sender.Enabled = True

单击按钮开始计算后,程序不会失去响应,你可以继续进行其他操作,一段时间后TextBox会显示计算结果。


本页地址:http://www.foxtable.com/webhelp/topics/6358.htm