同步函数示例
本节我们介绍同步函数,同步函数通常用于集中处理异步函数的运行结果。
上一节我们提出了一个问题,用异步函数进行累加,会因为冲突产生错误的结果。
那么如何得到正确的结果呢?
我们可以定义一个函数,这个函数同时只能有一个线程调用,如果有多个线程同时调用此函数,那么就必须排队,上一个线程调用完毕后,下一个线程才会继续,我们称这类函数称为同步函数。
有了同步函数,这样可以开启多个线程执行分别进行计算,然后将结果传递给此同步函数,统一进行处理,以避免上一节提到的冲突问题。
同步函数使用示例
1、定义Public变量
首先我们在全局代码中定义一个Public变量:
Public Total As Integer
2、定义同步函数
定义一个名为AddTotal的函数,其代码为:
Total =
Total
+ Args(0)
这个函数将在异步函数中被同步调用,用于累加各异步函数产生的结果。
3、定义异步函数
然后定义一个名为AddSubtotal的函数,这个函数将在主线程中被异步调用,其代码为:
Dim
Sum As
Integer
For
i As
Integer = 1
To 100
Sum
=
Sum +
1
Next
Functions
.BeginSyncExecute("AddTotal",Sum)
'调用同步函数AddTotal累加结果
4、测试结果
然后在命令窗口执行代码:
Total
= 0
For
i As
Integer = 1
To 100
Functions.AsyncExecute("AddSubtotal")
Next
在命令窗口删除以上代码,然后执行:
Return Total
现在你反复测试,会发现Total的值始终都等于10000。
5、执行过程与原理
主线程用AsyncExecute方法异步执行AddSubtotal函数100次,等于开启了100个子线程同时执行AddSubtotal方法,各子线程中的AddSubtotal方法完成数字累加后,用BeginSyncExecute方法同步执行函数AddTotal,将结果累加到全局变量Total,因为即使有多个子线程同时用BeginSyncExecute方法调用AddTotal,也只会有一个线程调用成功,其余需要排队等候执行,所以不会再有冲突发生。
6、慎用Sleep方法!
认真学习的用户可能已经想到了,这里为啥要两次执行? 直接在主线程用Sleep方法等2秒,待子线程执行完毕显示Total的值即可啊:
Total = 0
结果出乎意料,Total的值为0,为什么呢?
因为同步函数是在主线程中执行的,而上述代码暂停主线程2秒,所有子线程通过BeginSyncExecute调用AddTotal方法时,也都需要排队等候两秒才执行,所以2秒后主线程获取Total值时,可能还没有一个子线程将结果累加到Total变量,所以Total的结果为0。
同样的原因,我们不应该在同步函数中用Sleep方法,这会导致主线程和其他所有同步函数处于等待状态,总之除非用于测试,否则:
不要在主线程用Sleep!
不要在同步函数用Sleep!
自动等待异步函数执行完毕
作为一个面向非专业人士的开发平台,Foxtable并未提供等待异步函数执行完毕的功能,实际开发过程中也少有此种需要发生。
如果你确实需要在全部异步函数执行完毕后,自动执行特定的代码,可以参考下面的代码。
继续以前面的异步累加为例:
1、定义Public变量
首先我们在全局代码中定义一个Public变量:
Public
Total As
Integer
Public
TCount As
Integer
我们在这里增加了一个计数器变量TCount。
2、定义同步函数
定义一个名为AddTotal的函数,其代码为:
Total
= Total + Args(0)
TCount
= TCount -
1
If
Tcount = 0
Then
MessageBox.Show("计算完成,结果为:"
& Total)
End
If
这个函数将在异步函数中被同步调用,用于累加各异步函数产生的结果。
3、定义异步函数
然后定义一个名为AddSubtotal的函数,这个函数将在主线程中被异步调用,其代码为:
Dim
Sum As
Integer
For
i As
Integer = 1
To 100
Sum
=
Sum +
1
Next
Functions
.BeginSyncExecute("AddTotal",Sum)
'调用同步函数AddTotal累加结果
4、测试结果
然后在命令窗口执行代码:
Total
= 0
TCount =
100
For
i As
Integer = 1
To TCount
Functions.AsyncExecute("AddSubtotal")
Next
原理很简单,TCount变量的初始值为100,表示异步函数要调用100次,每次异步函数(AddSubtotal)执行完毕后,都会调用同步函数(AddTotal),此函数每执行一次,就将TCount减1,当TCount的值等于0,表示所有的100个异步函数都执行完毕了。