问题 在长循环期间,Flex等效于ProcessMessages和无响应的UI


我发现我的Flex应用程序的UI在非常长的处理循环(几十秒)内变得没有响应。例如,在处理非常大的XML文件并对每个元素执行某些操作时...

是否有“ProcessMessages”的等价物?也就是说,一个调用会告诉Flex继续响应UI事件,即使是在一些长循环的中间,这样UI也不会没有响应?

我知道Flex是单线程设计。这就是我正在寻找像ProcessMessages()这样的函数的原因 单线程可重入 应用程序(如VB或基于单线程消息循环的C ++应用程序)在长时间运行期间保持响应。

答案摘要

  1. 没有类似的内置功能 HandleEvents() 要么 ProcessMessages() 在Flex中。
  2. 使用某种回调机制迭代地处理长计算过程的块,同时在块之间屈服于运行时,从而使其能够响应,是在长计算期间维持响应UI的唯一方法。
  3. 完成上述方法的方法是:
    1. 使用 enterFrame event,只要Flex应用程序下面的Flash“movie”图层刷新其帧(类似于20fps),就会调用该事件。
    2. 使用计时器。
    3. 运用 UIComponent.callLater() 哪个计划工作要“以后”完成。 (作为文档 Queues a function to be called later. Before each update of the screen, Flash Player or AIR calls the set of functions that are scheduled for the update.
    4. 使用故意触发的鼠标/键盘事件来创建伪“工作线程”,如 这个例子

如果有进一步的建议,或者我遗漏了任何东西,请随时编辑这个(现在的)维基片。


6923
2018-02-18 10:40


起源



答案:


问题是Flash是单线程的,即在代码的一部分运行之前,不能进行其他处理。你会以某种方式将处理分解成更小的块并执行这些块,比如说 enterFrame 事件。

编辑:我担心低估这个(或西蒙的)答案并没有改变这在AS3中不可行的事实。读 本文 有关问题的更多见解。该文章还包括一个名为PseudoThread的简单“库”,它有助于执行长背景计算。不过,你仍然需要将问题分解成更小的部分。


6
2018-02-18 15:28



是,但与此同时,我无法在flex中创建自定义事件,并且这个自定义事件处理程序附加了我想要的代码?并在每'n'秒后触发事件。这将确保它是异步调用,并没有真正关心被调用的函数,因为事件处理程序本质上是异步的; - Neeraj
不,事件处理程序在AS3中不是异步的,因为它们不会中断任何正在运行的AS3代码。事件在事件队列中收集,第一个事件被取出,其处理程序完全运行,然后引擎移动到下一个事件。 - David Hanak


答案:


问题是Flash是单线程的,即在代码的一部分运行之前,不能进行其他处理。你会以某种方式将处理分解成更小的块并执行这些块,比如说 enterFrame 事件。

编辑:我担心低估这个(或西蒙的)答案并没有改变这在AS3中不可行的事实。读 本文 有关问题的更多见解。该文章还包括一个名为PseudoThread的简单“库”,它有助于执行长背景计算。不过,你仍然需要将问题分解成更小的部分。


6
2018-02-18 15:28



是,但与此同时,我无法在flex中创建自定义事件,并且这个自定义事件处理程序附加了我想要的代码?并在每'n'秒后触发事件。这将确保它是异步调用,并没有真正关心被调用的函数,因为事件处理程序本质上是异步的; - Neeraj
不,事件处理程序在AS3中不是异步的,因为它们不会中断任何正在运行的AS3代码。事件在事件队列中收集,第一个事件被取出,其处理程序完全运行,然后引擎移动到下一个事件。 - David Hanak


我可以肯定地告诉你,从Flex 3开始,没有类似的内置结构 ProcessMessages 您正在描述的功能。

解决此问题的最常见方法是将正在处理的任何工作拆分为“工作”任务队列,并将“工作管理器”拆分为控制队列。当每个“worker”完成其处理时,worker队列管理器将下一个worker从队列中弹出并在a中执行 callLater() 调用。这将产生类似于“屈服于主线​​程”的效果,并允许您的UI接收事件并做出响应,同时仍允许在将控制权返回给工作者时继续处理。

一旦你有了这个工作,你可以做一些测试和分析,以确定你的应用程序是否可以在调用之前执行多个工作程序的运行 callLater(),并将此逻辑封装在工作队列管理器中。例如,在我们的这种模式的实现中(队列中有几百个工作者),我们能够通过在“屈服于主线​​程”之前执行4个工作人员来更快地完成处理并具有可比较的感知性能 callLater(),但这完全取决于工人正在做的工作的范围和性质。


4
2018-02-18 10:40



你如何实现callLater? - Assaf Lavie
这是UIComponent上的一个方法。 livedocs.adobe.com/flex/3/langref/mx/core/... - erikprice


ActionScript的流程模型是单线程的,所以答案是否定的。最好的办法是,如果可以的话,要么推迟服务器上的异步任务,要么在长循环运行时弹出等待光标,或者将你的进程分解成一些不那么具有侵入性的小块,或者执行在用户不太可能感觉到效果的时刻长时间运行的任务(例如app启动)。


2
2018-02-18 12:05



它是单线程的事实并不能说明缺少ProcessMessages函数。这样的功能是合适的 只要 对于具有处理用户事件的消息循环的单线程应用程序。 IOW,它适用于单线程VB应用程序,为什么不用于Flex? - Assaf Lavie


Actionscript是单线程设计,没有任何downvoting答案会改变它。

为了兼容性,您最好的办法是尝试将处理拆分为更小的块,并迭代进行处理。

如果你绝对需要穿线它可以 有点 可以在Flash Player 10中使用 Pixel Bender 过滤器。这些将在一个单独的线程上运行,一旦完成就可以给你一个回调。
我相信它们非常适合“硬核”处理任务,因此它们可能很适合您的目的。 但是,它们会对您的代码提出另外一组要求,因此您可能更好地执行计算的小“桶”。


2
2018-02-18 22:00



没有人争论flex是单线程的事实,jeez。再次阅读帖子,就是这样 因为 它是单线程,消息泵功能是需要的。问题是是否有一个。我不需要也不想在flex中使用多个线程,只是一种使ui响应的方法。 - Assaf Lavie


Flash Player中没有等效功能。按照设计,Flash Player在渲染到屏幕之间交替,然后为每个帧运行所有代码。运用 Event.ENTER_FRAME 显示对象上的事件,或 Timer 其他地方的对象,是打破很长时间计算的最佳选择。

值得注意的是,ActionScript中的某些事件有一个 updateAfterEvent() 功能与以下描述:

如果已修改显示列表,则指示Flash Player或AIR运行时在此事件处理完成后呈现。

尤其是, TimerEventMouseEvent,和 KeyboardEvent 支持 updateAfterEvent()。可能还有其他人,但那些是我通过快速搜索找到的。


1