如何在 Actionscript 中添加处理超过 15 秒的时间延迟?

Posted

技术标签:

【中文标题】如何在 Actionscript 中添加处理超过 15 秒的时间延迟?【英文标题】:How to add time delay to process more than 15 second in Actionscript? 【发布时间】:2019-10-07 00:48:47 【问题描述】:

所以我有以下脚本来获取数组的所有组合: '''

var value = new Array(40)
for (var i=0;i<value.length;i++)
    value[i]=i;

var comb_list = getAllComb(value,24);
trace(comb_list)
function getAllComb(values:Array, r:int):Array
    var n = values.length;
    var result = new Array();
    var a = new Array(r);

    // initialize first combination
    for (var i = 0; i < r; i++) 
        a[i] = i;
    

    i = r - 1; // Index to keep track of maximum unsaturated element in array
    // a[0] can only be n-r+1 exactly once - our termination condition!
    var count = 0;
    while (a[0] < n - r + 1) 
        // If outer elements are saturated, keep decrementing i till you find unsaturated element
        while (i > 0 && a[i] == n - r + i) 
            i--;
        
        result.push(a.slice())// pseudo-code to print array as space separated numbers
        count++;
        a[i]++;
        // Reset each outer element to prev element + 1
        while (i < r - 1) 
            a[i + 1] = a[i] + 1;
            i++;
        
    
    return result;

'''

运行上面的脚本会得到我:

错误:错误 #1502:脚本执行的时间超过了默认的 15 秒超时时间。

如何每经过 14 秒添加时间延迟,以便我可以运行脚本?因此,经过 14 秒后,程序将等待 50 毫秒然后继续。

任何帮助表示赞赏。

【问题讨论】:

通常,Flash Player 不是多线程环境。其操作如下:代码执行>图形渲染>代码执行>图形渲染>等等。如果你运行一个无限循环,下一帧永远不会到来,这是不正常的。 【参考方案1】:

如果您使用的是 Adob​​e Animate (Flash),您可以从发布设置页面更改“脚本时间限制”。

【讨论】:

【参考方案2】:

所以,有一个简单的(嗯,几乎如此)和有效的示例,说明如何将繁重的计算部分与主线程分开,以便主线程(也处理 UI 和用户输入等外部事件)能够顺利运行,同时能够阅读引擎盖下的繁重计算的进度和结果。它也是单个类的形式,这可能会有点令人困惑(直到您了解它的工作原理)但仍然易于处理和修改。

虽然后台 AVM 遵循相同的执行流程(代码执行 > 图形渲染 > 代码执行 > 图形渲染 > 等等),但没有要渲染的图形,因此无需限制代码执行时间。因此,Worker 线程不受 15 秒的限制,以某种方式解决了问题。

package

    import flash.events.Event;
    import flash.display.Sprite;
    import flash.utils.ByteArray;

    import flash.concurrent.Mutex;

    import flash.system.Worker;
    import flash.system.WorkerDomain;

    public class MultiThreading extends Sprite
    
        // These variables are needed by both the main and
        // subservient threads and will actually point to
        // the very same object instances, though from
        // the different sides of this application.
        private var B:ByteArray;
        private var W:Worker;
        private var M:Mutex;

        // Constructor method.
        public function MultiThreading() 
        
            super();

            // This property is 'true' for the main thread
            // and 'false' for any Worker instance created.
            if (Worker.current.isPrimordial)
            
                prepareProgress();
                prepareThread();
                startMain();
            
            else
            
                startWorker();
            
        

        // *** THE MAIN THREAD *** //

        private var P:Sprite;
        private var F:Sprite;

        // Prepares the progress bar graphics.
        private function prepareProgress():void
        
            F = new Sprite;
            P = new Sprite;

            P.graphics.beginFill(0x0000FF);
            P.graphics.drawRect(0, 0, 100, 10);
            P.graphics.endFill();
            P.scaleX = 0;

            F.graphics.lineStyle(0, 0x000000);
            F.graphics.drawRect(0, 0, 100, 10);

            F.x = 10;
            F.y = 10;
            P.x = 10;
            P.y = 10;

            addChild(P);
            addChild(F);
        

        // Prepares the subservient thread and shares
        // the ByteArray (the way to pass messages)
        // and the Mutex (the way to access the shared
        // resources in a multi-thread environment
        // without stepping on each others' toes).
        private function prepareThread():void
        
            M = new Mutex;
            B = new ByteArray;
            B.shareable = true;
            B.writeObject(incomingMessage);

            W = WorkerDomain.current.createWorker(loaderInfo.bytes);
            W.setSharedProperty("message", B);
            W.setSharedProperty("lock", M);
        

        // Starts listening to what the background thread has to say
        // and also starts the background thread itself.
        private function startMain():void
        
            addEventListener(Event.ENTER_FRAME, onFrame);

            W.start();
        

        private var incomingMessage:Object = ready:0, total:100;

        private function onFrame(e:Event):void
        
            // This method runs only 20-25 times a second.
            // We need to set a lock on the Mutex in order
            // to read the shared data without any risks
            // of colliding with the thread writing the
            // same data at the same moment of time.
            M.lock();

            B.position = 0;
            incomingMessage = B.readObject();

            M.unlock();

            // Display the current data.
            P.scaleX = incomingMessage.ready / incomingMessage.total;
            P.alpha = 1 - 0.5 * P.scaleX;

            // Kill the thread if it signalled it is done calculating.
            if (incomingMessage.terminate)
            
                removeEventListener(Event.ENTER_FRAME, onFrame);

                W.terminate();

                B.clear();

                B = null;
                M = null;
                W = null;
            
        

        // *** THE BACKGROUND WORKER PART *** //

        // I will use the same W, M and B variables to refer
        // the same Worker, Mutex and ByteArray respectively,
        // but you must keep in mind that this part of the code
        // runs on a different virtual machine, so it is the
        // different class instance thus its fields are not
        // the same quite as well.

        // Initialization.
        private function startWorker():void
        
            W = Worker.current;
            M = W.getSharedProperty("lock");
            B = W.getSharedProperty("message");

            // Before starting the heavy calculations loop
            // we need to release the main thread which is
            // presently on W.start() instruction. I tried
            // without it and it gives a huuuge lag before
            // actually proceeding to intended work.
            addEventListener(Event.ENTER_FRAME, onWorking);
        

        private function onWorking(e:Event):void
        
            removeEventListener(Event.ENTER_FRAME, onWorking);

            var aMax:int = 10000000;

            // Very very long loop which might run
            // over the course of several seconds.
            for (var i:int = 0; i < aMax; i++)
            
                // This subservient thread does not actually need to
                // write its status every single loop, so lets don't
                // explicitly lock the shared resources for they
                // might be in use by the main thread.
                if (M.tryLock())
                
                    B.position = 0;
                    B.writeObject(ready:i, total:aMax);

                    M.unlock();
                
            

            // Let's notify the main thread that
            // the calculations are finally done.
            M.lock();

            B.position = 0;
            B.writeObject(ready:i, total:aMax, terminate:true);

            M.unlock();

            // Release the used variables and prepare to be terminated.
            M = null;
            B = null;
            W = null;
        
    

【讨论】:

【参考方案3】:

该错误与您的脚本需要时间延迟无关,问题是您的 while 循环使您的脚本无响应超过 15 秒,从而触发了脚本超时错误。动作脚本只允许您的脚本执行 15 秒。

您的第一个 while 循环看起来有问题,我不清楚 a[0] 的值如何更改以结束循环。在循环中添加一个中断或确保条件更改以允许循环结束,您应该解决您的问题。如果它们只应该在找到不饱和值后运行一次,您还可以考虑将 continue 语句添加到嵌入式 while 循环中。

就个人而言,由于您使用的是 ActionScript,我建议您使用对象和侦听器进行值更改,而不是遍历数组检查更改。

您还可以为您的 while 循环添加手动超时,但需要包含逻辑以使其从中断处继续。

//Set timer to 14 seconds
timeout = getTimer() + 14000;
while(true && timeout > getTimer())
    trace("No Error");

【讨论】:

问题是,如果我将 40 和 24 更改为更小的数字 - 例如,更改为 10 和 5。程序成功运行,我得到了正确的结果(所以,我得出结论循环最终会停止)。我猜想 C(40,24) 是一个非常大的数字这一事实导致程序无响应。这就是为什么我很好奇有没有办法在函数中添加“等待”。 听起来操作很繁重。我通常发现在 actionscript 中迭代数组很慢。如果它只需要通过 10 个值运行 while 循环,那么它可以在 15 秒内完成,并且没有错误,听起来像是要检查 40/24 个值,它需要超过 15 秒。您需要以一种限制它在一个循环中检查多少值的方式重新编写代码。同样,使用对象和侦听器将是解决此问题的简单方法,但如果您真的想使用 while 循环,则可能会使用 getTimer() 函数来中断循环 同意@dprogramzis ,您必须限制循环经过的循环数,保存循环整数并恢复下一帧。由于进程的繁重,计时器也有可能无法准确工作。最好的方法是限制每帧的周期。 @user1234567 不。如果这些计算THAT 繁重,最好的方法是诉诸多线程。首先,这是设计具有如此繁重计算的 AS3 应用程序而不会导致 UI 卡顿的正确方法,其次这是很酷的事情,最后但并非最不重要的是,在 FP30 中 getTimer的成本> 确实增加了一千倍,每次循环迭代都调用它本身就是一个巨大的性能问题:forums.adobe.com/thread/2499947 @Organis 我不确定你的意思,AS3 不是多线程的,也不支持它。这实际上取决于此功能需要运行的频率。您可以使用 Worker 类来生成虚拟实例并伪造多处理来处理数据,但是您必须开始处理诸如并发之类的事情。我仍然认为使用带有侦听器的类是比手动迭代数组更优雅的解决方案。因为事件的 CPU 密集度低于轮询。

以上是关于如何在 Actionscript 中添加处理超过 15 秒的时间延迟?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UILoader 中添加两个 UILoader 并使用 actionscript 3 保存 UILoader 的内容

如何使用非 MXML 而是 Actionscript 在 Flex 中创建动态状态并为其添加按钮?

Actionscript - 如何在 TabNavigator 的选项卡上设置单击处理程序?

Actionscript 3 - 如何在删除该事件后保留该事件的值

Actionscript 3.0 - 检测已放置在舞台上的多个实例并将它们添加到数组中

ActionScript:如何在每个 Time 函数起作用时重置Interval?