【AS3多线程探秘】——系列教程,共五篇
目录
Worker?Why?
如何开始呢?那么我就先说说我对AS3里面多线程的理解和看法吧。
1. 多线程是为了保证电脑运行不卡和速度更快
首先,多线程大家知道,可以通过线程的方式同时运行多个代码块,以保证在复杂计算时候程序的稳定运行(画面不卡等),如果把任务分块交给多个线程则可以保证速度更快(前提是有多个处理器)。
2. AS3中最好只使用一个或者两个线程
然而,AS3的多线程可能不像其他语言那么好用(我猜的),AS3的多线程的大致思路就是,在Flash Player中每一个线程都有一个独立的AVM2虚拟机(原本只有两个虚拟机,一个AVM1用于运行AS2.0的东西,一个AVM2用于运行3.0的东西),也就是每创建一个线程(Worker)就会多创建一个AVM2,所以Adobe官方也建议大家在原来的基础上再使用一个或者两个线程(Worker)就好,多了会很吃电脑内存。
3. 多线程的两个概念并发和并行
多线程分为并发和并行。
并发是处理器在多个线程之间跳转执行代码。
并行是在多个处理器的时候可以多处理器同时运行不同的线程(真正的代码同时运行)。
虽然多线程应该是代码被设计成多部分同时进行,但实际对于多数程序或者AS来说,只需要一个子线程在代码运行比较卡的时候让程序不卡。
注意:在之后帖子的三个fla测试练习中,我对AS3并发和并行的理解可能有些错误,因为我在官方的API中看到了并行这个词,我在想是否AS3已经实现了多处理器的时候的并行技术
AS3中多线程的设计
先来梳理一下,Adobe是如何设计AS3的多线程的。
AS3将多线程分为三部分:
一个是线程对象Worker,
一个是线程之间的通信(MessageChannel和其他的通信方法),
一个是创建和访问线程对象的机制WorkerDomain对象。
默认我们不创建多线程的情况,其实本身程序就运行着一个Worker(这个是原始的或者说是主的)。
下面我会将默认的Worker称之为主线程,而额外创建的Worker称之为子线程,因为AS3是并发,所以从程序设计的角度来说,AS的代码应该是都在主线程中,而额外的线程仅仅是在运行很复杂计算的时候使用,所以称之为子比较合理。
1. WorkerDomain对象
之所以先说这个,是因为要创建子线程(也就是额外的线程),必须使用WorkerDomain对象。
1.1 静态属性访问WorkerDomain
WorkerDomain不可以被new,只能通过静态属性 current 进行访问,唯一的实例对象。
1.2 判断是否支持多线程
使用静态属性 isSupported 可以判断是否支持并发。
1.3 使用 createWorker() 方法创建子线程
使用 createWorker() 方法可以创建额外的线程,也就是我们将使用它创建一个子线程对象Worker,必须通过SWF的字节数组才可以创建Worker,有三种常用的方式可以创建子线程(具体方法见API):
• 使用 [Embed] 元标记将 .swf 文件作为 ByteArray 嵌入在应用程序中;
• 使用 URLLoader 加载外部 SWF 文件(这是我推荐和使用的方式);
• 将单个 swf 同时用作原始 worker 和后台 worker。
2. Worker对象
这是最核心的对象,但其实也很简单,因为它的属性和方法并不多,也都很关键。
2.1 静态属性访问Worker
使用静态属性 current 可以访问包含当前代码的Worker,也就是在主线程中的代码可以通过这个属性访问到主线程的Worker对象实例,而子线程的代码可以通过这个属性访问到子线程的Worker对象实例。
2.2 判断是否为原始的Worker
使用 isPrimordial 属性确定当前获取的Worker是否为原始的Worker,也就是是否是主线程。
2.3 判断是否支持并发/并行(有疑惑)
使用 isSupported 属性判断是否支持并发/并行,我在官方API看到的是并行,但是我的一直理解是AS3只实现了并发。。但是这个不重要,如果实现了更好,没实现也没办法不是吗。
2.4 判断Worker的当前状态
使用 state 判断Worker的状态,有三种,一种是新的线程(什么代码都没有执行 WorkerState.NEW),一种是正在运行的线程(WorkerState.RUNNING),一种是被停止的线程(WorkerState.TERMINATED)。
2.5 启动和停止Worker
start() 和 terminate() 方法可以启动和停止Worker,原始的Worker我估计没法和自行调用启动和停止(我猜的,你们可以试验)。
2.6 还有几个方法是跟通信机制有关的,所以在下面讲
3. 线程Worker之间的通信机制
线程与线程之间是完全的独立运行,所以当一个子线程完成了任务,就要把任务结果返回给主线程,于是就需要一个通信机制了。AS3的Worker有三种通信机制,用来发送消息和传送数据:
• 共享属性
• MessageChannel
• 可共享 ByteArray
3.1 共享属性
[官方介绍]
每个 worker 都有可以从该 worker 自身及其他 worker 设置和读取的一组内部命名值。您可以使用 setSharedProperty() 方法来设置值并使用 getSharedProperty() 方法来读取值
[TKCB]
其实就是当创建了子线程对象Worker后,使用这个子worker.setSharedProperty() 方法给里面设置传入数据对象,有两个参数一个是传入参数的名称字符串,用于之后的get方法获取,另一个是对象参数。
在子线程的代码中,可以使用Worker.current.getSharedProperty() 方法获取这个主线程里面传入的数据对象,通过set设置的名称字符串获取。
但是这个机制通常只用于,在子线程Worker还没启动的时候,传递下面的机制的对象 MessageChannel 给子线程。
因为使用这个set和get不能进行侦听,所以子线程就必须创建一个无线的Timer对象进行不断地get数据对象,所以很不方便。
3.2 MessageChannel
[官方介绍]
MessageChannel 对象允许您将单向消息和数据从一个 worker 发送到另一个 worker。接收 worker 中的代码可以侦听当有消息到达时要通知的事件。要创建 MessageChannel 对象,请使用 createMessageChannel() 方法。
[TKCB]
这是一个用于连接两个进程的通道对象,但它是单向的,也就是说如果想要主和子互通消息,必须创建两个这个对象(具体创建方式见API或者我的练习文件)。
使用上面提到的第一个通信机制将两个通道对象传入子线程中,这样子线程就可以侦听这两个对象,然后获取和发送消息和传送数据对象了。
这个是我推荐和使用的主要通信机制。
3.3 可共享 ByteArray
[官方介绍]
如果 ByteArray 对象的 shareable 属性为 true,则所有 worker 中该 ByteArray 的实例都使用相同的底层内存。由于多个 worker 中的代码可以同时访问共享内存,因此您的代码应使用 ByteArray.shareable 属性说明中描述的机制,以避免发生数据意外更改问题。
[TKCB]
如果子线程运算后的返回对象是ByteArray,则使用共享可以减少很多内存的消耗。
4. 最后总结一下
其实也挺简单,代码的主要基本结构应该是这样:
主线程:
• 判断是否支持子线程,
• 获取主线程对象,
• 创建子线程对象,
• 创建两个通信对象,
• 侦听子线程的通信对象(只侦听一个通信对象,根据侦听的结果运行其他代码),
• 给子线程传入通信对象,
• 启动子线程。
子线程:
• 获取子线程对象,
• 获取两个通信对象,
• 侦听两个线程的通信对象(因为子线程牵扯到收到消息和数据,然后运行代码计算,之后返回消息和数据),
• 根据侦听,然后运行不同的代码(或许是复杂的计算或者是返回消息和数据)。
参考资料和帖子
AS3多线程快速入门(一):Hello World[译]
(已失效)
http://bbs.9ria.com/forum.php?mo ... 4587&fromuid=273124(已失效)
AS3多线程快速入门(二):图像处理[译]
(已失效)
http://bbs.9ria.com/forum.php?mod=viewthread&tid=145065(已失效)
AS3并发机制的通俗解释
(已失效)
http://bbs.9ria.com/thread-139324-1-1.html(已失效)
AS3.0多线程作用有多大?
(已失效)
http://bbs.9ria.com/thread-147591-1-1.html(已失效)
听我说一些废话吧
多线程很不错,真好,虽然Adobe的多线程有一些地方会坑人,但至少实现了不是吗。
免费是最昂贵的
银子还是要收的,因为
“免费的东西最昂贵” ,请深刻理解这句话的含义!!!
广告QQ(TKCB):2414268040(欢迎和我聊天交流,有朋自远方来不亦说乎)
QQ群:96759336(AS3殿堂之路,Flash Animate AS3 AIR 技术交流)
QQ群:705730359(H5天路历程,HTML5 CSS3 JaveScript 技术交流)
QQ群:463560360(King系列软件分享交流,TKCB 出品的 King 系列软件分享、使用、交流、反馈等)