Неко и haxe.Timer.delayed()

Как известно каждому разработчику Haxe, вы можете использовать haxe.Timer.delayed() для задержки вызова функции на некоторое время. Но этой функции у Неко вообще нет. Есть ли способ добиться таких же результатов?


person vava    schedule 22.10.2008    source источник


Ответы (4)


Надо сначала проверить, но

function delayed(f, time) {
   neko.vm.Thread.create(function() {
       neko.Sys.sleep(time);
       f();
   });
}

может быть самым близким из возможных. Единственным недостатком является то, что приложение становится многопоточным, что может привести к серьезным проблемам.

person vava    schedule 22.10.2008
comment
Какие проблемы, если вы создаете поток только для этой цели? - person Tom; 17.05.2010
comment
@Tom, функция f() будет выполняться в контексте другого потока. Он может использовать общие ресурсы или вызывать другие функции, которые используют общие ресурсы. Ничего особенного в этом случае, просто обычное многопоточное приложение. - person vava; 17.05.2010
comment
В этом случае лучше всего создать приложение Neko с haXe. Почему бы вам не сделать это? - person Tom; 18.05.2010
comment
@ Том, я так и делаю :) Но у haxe.Timer есть только один метод под neko или php, stamp(). delayed() доступен на всех других платформах, но не в неко. - person vava; 18.05.2010
comment
Ах я вижу. В таком случае я рекомендую вам создать собственный класс Timer для neko. Статический конструктор создаст новый поток, который просто зацикливается с определенным интервалом, отслеживая метки времени и регистрируя вновь добавленные таймеры. Удачи. Если вы собираетесь это сделать, было бы здорово, если бы вы могли поделиться классом с сообществом haXe. - person Tom; 18.05.2010

Я подумал о вашей проблеме и думаю, что лучший способ — создать собственный класс Timer для Neko. Я сделал для вас класс Timer:

NekoTimer.hx

package;
import neko.Sys;

    class NekoTimer 
    {
    private static var threadActive:Bool = false;
    private static var timersList:Array<TimerInfo> = new Array<TimerInfo>();
    private static var timerInterval:Float = 0.1;

    public static function addTimer(interval:Int, callMethod:Void->Void):Int
    {
        //setup timer thread if not yet active
        if (!threadActive) setupTimerThread();

        //add the given timer
        return timersList.push(new TimerInfo(interval, callMethod, Sys.time() * 1000)) - 1;
    }

    public static function delTimer(id:Int):Void
    {
        timersList.splice(id, 1);
    }

    private static function setupTimerThread():Void
    {
        threadActive = true;
        neko.vm.Thread.create(function() {
            while (true) {
                Sys.sleep(timerInterval);
                for (timer in timersList) {
                    if (Sys.time() * 1000 - timer.lastCallTimestamp >= timer.interval) {
                        timer.callMethod();
                        timer.lastCallTimestamp = Sys.time() * 1000;
                    }
                }
            }
        });
    }
}

private class TimerInfo
{
    public var interval:Int;
    public var callMethod:Void->Void;
    public var lastCallTimestamp:Float;

    public function new(interval:Int, callMethod:Void->Void, lastCallTimestamp:Float) {
        this.interval = interval;
        this.callMethod = callMethod;
        this.lastCallTimestamp = lastCallTimestamp;
    }
}

Назовите это так:

package ;

import neko.Lib;

class Main 
{
    private var timerId:Int;

    public function new()
    {
        trace("setting up timer...");
        timerId = NekoTimer.addTimer(5000, timerCallback);
        trace(timerId);

        //idle main app
        while (true) { }
    }

    private function timerCallback():Void
    {
        trace("it's now 5 seconds later");
        NekoTimer.delTimer(timerId);
        trace("removed timer");
    }

    //neko constructor
    static function main() 
    {
        new Main();
    }
}

Надеюсь, это поможет.

Примечание: этот имеет точность 100 мс. Вы можете увеличить это, уменьшив настройку timerInterval.

person Tom    schedule 18.05.2010
comment
Как бы я ни поддерживал ваши усилия, это ничего не решает :) Обратный вызов все равно будет выполняться в контексте другого потока, того, который вы создали в классе, так как вы не можете перенести его в основной. - person vava; 19.05.2010
comment
На самом деле я понял это, когда ложился спать... Я собираюсь задать этот вопрос в списке рассылки haxe. - person Tom; 19.05.2010

Я также использовал этот класс и обнаружил одну проблему. Поскольку это не полностью реальное время, он приостанавливает интервал, вызывает функцию и снова приостанавливает интервал. Таким образом, в зависимости от того, сколько времени занимает функция, которую вы запускаете, она работает медленнее или быстрее.

Я решил это, заменив строку 39 следующим образом:

//timer.lastCallTimestamp = Sys.time() * 1000;
timer.lastCallTimestamp = timer.lastCallTimestamp + timer.interval;
person Raul    schedule 19.12.2013

Да, я ничего не знаю, кроме того, что вы упомянули в своем первом ответе. В Linux вы можете использовать SIGALARM, но это не выглядит тривиально, 100% чистый код C, и с ним нужно обращаться очень осторожно, чтобы избежать сбоя виртуальной машины.

person Michael Pliskin    schedule 06.11.2008