Quellcode durchsuchen

support delay for eventloop

lyon vor 3 Jahren
Ursprung
Commit
6d3d8b3658

+ 43 - 0
examples/eventloop/delay1.py

@@ -0,0 +1,43 @@
+import time
+from eventloop import EventLoop
+
+run_time = 0
+
+eventloop.set_debug(True)
+
+
+def test_func(arg1, arg2):
+    global run_time
+    run_time += 1
+    print("Running test function with arguments:", arg1, arg2)
+    return arg1 + arg2
+
+
+def test_func2(arg1, arg2):
+    print("test function 2 with arguments:", arg1, arg2)
+    return arg1 + arg2
+
+
+def test_callback(res):
+    print("Running test callback function", res)
+    assert res == "Hello World"
+
+
+# Test case 2: Add and run a periodic task
+
+eventloop.start_new_task_once(
+    test_func, ("Hello", " World"),
+    callback=test_callback,
+    delay_ms=2000
+)
+
+eventloop.start_new_task(
+    test_func2, ("Hello", " World"),
+    is_periodic=True,
+    period_ms=200,
+    callback=test_callback
+)
+
+# Sleep for enough time to allow the periodic task to run multiple times
+while run_time < 1:
+    time.sleep(0.1)

+ 1 - 0
package/eventloop/README.md

@@ -0,0 +1 @@
+# eventloop

+ 60 - 22
package/eventloop/eventloop.py

@@ -14,8 +14,9 @@ class EventTask:
     _period_ms = None
     _is_periodic = False
     _last_call_time = 0
+    _delay_ms = None
 
-    def __init__(self, func, callback, args, period_ms):
+    def __init__(self, func, callback, args, period_ms, delay_ms):
         """
         :param func: function to be called
         :param callback: callback function
@@ -26,6 +27,12 @@ class EventTask:
         self._callback = callback
         self._args = args
         self._period_ms = period_ms
+        self._delay_ms = delay_ms
+        if not delay_ms is None:
+            if period_ms is None:
+                period_ms = 0
+            self._last_call_time = time.tick_ms() - period_ms + delay_ms
+            _debug('last_call_time for delay:', self._last_call_time)
         if period_ms != None:
             self._is_periodic = True
 
@@ -49,7 +56,7 @@ class EventLoop:
         self._period_ms = period_ms
         self._thread_stack = thread_stack
 
-    def _add_task(self, task_name, func, callback, args, period_ms):
+    def _add_task(self, task_name, func, callback, args, period_ms, delay_ms):
         if task_name == None:
             self._uuid += 1
             task_name = str(self._uuid)
@@ -58,10 +65,18 @@ class EventLoop:
         _debug('callback', callback)
         _debug('args', args)
         _debug('period_ms', period_ms)
-        new_task = EventTask(func, callback, args, period_ms)
+        _debug('delay_ms', delay_ms)
+        new_task = EventTask(func, callback, args, period_ms, delay_ms)
         self._tasks[task_name] = new_task
 
-    def start_new_task(self, func, args, is_periodic=True, period_ms=1000, callback=None, task_name=None):
+    def start_new_task(self,
+                       func, args,
+                       is_periodic=True,
+                       period_ms=1000,
+                       callback=None,
+                       task_name=None,
+                       delay_ms=None
+                       ):
         """
         Add a task to EventLoop
         :param task_name: name of task
@@ -71,11 +86,16 @@ class EventLoop:
         :param args: arguments of func
         """
         if is_periodic:
-            self._add_task(task_name, func, callback, args, period_ms)
+            self._add_task(task_name, func, callback,
+                           args, period_ms, delay_ms)
         else:
-            self._add_task(task_name, func, callback, args, None)
+            self._add_task(task_name, func, callback, args, None, delay_ms)
 
-    def start_new_task_once(self, func, args, callback=None, task_name=None):
+    def start_new_task_once(self,
+                            func, args,
+                            callback=None,
+                            task_name=None,
+                            delay_ms=None):
         """
         Add a task to EventLoop, run once
         :param task_name: name of task
@@ -83,9 +103,10 @@ class EventLoop:
         :param callback: callback function
         :param args: arguments of func
         """
-        self.start_new_task(func, args, False, None, callback, task_name)
+        self.start_new_task(func, args, False, None,
+                            callback, task_name, delay_ms)
 
-    def start_new_task_periodic(self, func, args, period_ms=1000, callback=None, task_name=None):
+    def start_new_task_periodic(self, func, args, period_ms=1000, callback=None, task_name=None, delay_ms=None):
         """
         Add a task to EventLoop, run periodically
         :param task_name: name of task
@@ -94,7 +115,8 @@ class EventLoop:
         :param callback: callback function
         :param args: arguments of func
         """
-        self.start_new_task(func, args, True, period_ms, callback, task_name)
+        self.start_new_task(func, args, True, period_ms,
+                            callback, task_name, delay_ms)
 
     def remove_task(self, task_name):
         """
@@ -112,13 +134,14 @@ class EventLoop:
         while not self._need_stop:
             tick = time.tick_ms()
             for task_name, task in self._tasks.items():
-                if task._is_periodic:
-                    if tick - task._last_call_time > task._period_ms:
-                        self._run_task(task)
-                        task._last_call_time = tick
-                else:
+                if tick - task._last_call_time > task._period_ms:
+                    _debug('run_task', task_name)
+                    _debug('tick', tick)
+                    _debug('last_call_time', task._last_call_time)
                     self._run_task(task)
-                    self.remove_task(task_name)
+                    task._last_call_time = tick
+                    if not task._is_periodic:
+                        self.remove_task(task_name)
             if self._need_stop:
                 break
             time.sleep_ms(self._period_ms)
@@ -171,7 +194,13 @@ def _get_default_event_loop():
     return g_default_event_loop
 
 
-def start_new_task(func, args, is_periodic=True, period_ms=1000, callback=None, task_name=None):
+def start_new_task(func, args,
+                   is_periodic=True,
+                   period_ms=1000,
+                   callback=None,
+                   task_name=None,
+                   delay_ms=None
+                   ):
     """
     Add a task to EventLoop
     :param task_name: name of task
@@ -182,10 +211,14 @@ def start_new_task(func, args, is_periodic=True, period_ms=1000, callback=None,
     """
     eventloop = _get_default_event_loop()
     eventloop.start_new_task(func, args, is_periodic,
-                             period_ms, callback, task_name)
+                             period_ms, callback, task_name, delay_ms)
 
 
-def start_new_task_once(func, args, callback=None, task_name=None):
+def start_new_task_once(func, args,
+                        callback=None,
+                        task_name=None,
+                        delay_ms=None
+                        ):
     """
     Add a task to EventLoop, run once
     :param task_name: name of task
@@ -194,10 +227,15 @@ def start_new_task_once(func, args, callback=None, task_name=None):
     :param args: arguments of func
     """
     eventloop = _get_default_event_loop()
-    eventloop.start_new_task_once(func, args, callback, task_name)
+    eventloop.start_new_task_once(func, args, callback, task_name, delay_ms)
 
 
-def start_new_task_periodic(func, args, period_ms=1000, callback=None, task_name=None):
+def start_new_task_periodic(func, args,
+                            period_ms=1000,
+                            callback=None,
+                            task_name=None,
+                            delay_ms=None
+                            ):
     """
     Add a task to EventLoop, run periodically
     :param task_name: name of task
@@ -208,7 +246,7 @@ def start_new_task_periodic(func, args, period_ms=1000, callback=None, task_name
     """
     eventloop = _get_default_event_loop()
     eventloop.start_new_task_periodic(
-        func, args, period_ms, callback, task_name)
+        func, args, period_ms, callback, task_name, delay_ms)
 
 
 def remove_task(task_name):

+ 3 - 0
port/linux/.vscode/settings.json

@@ -127,5 +127,8 @@
     ],
     "[toml]": {
         "editor.defaultFormatter": "tamasfe.even-better-toml"
+    },
+    "[python]": {
+        "editor.defaultFormatter": "ms-python.python"
     }
 }

+ 60 - 22
port/linux/package/pikascript/eventloop.py

@@ -14,8 +14,9 @@ class EventTask:
     _period_ms = None
     _is_periodic = False
     _last_call_time = 0
+    _delay_ms = None
 
-    def __init__(self, func, callback, args, period_ms):
+    def __init__(self, func, callback, args, period_ms, delay_ms):
         """
         :param func: function to be called
         :param callback: callback function
@@ -26,6 +27,12 @@ class EventTask:
         self._callback = callback
         self._args = args
         self._period_ms = period_ms
+        self._delay_ms = delay_ms
+        if not delay_ms is None:
+            if period_ms is None:
+                period_ms = 0
+            self._last_call_time = time.tick_ms() - period_ms + delay_ms
+            _debug('last_call_time for delay:', self._last_call_time)
         if period_ms != None:
             self._is_periodic = True
 
@@ -49,7 +56,7 @@ class EventLoop:
         self._period_ms = period_ms
         self._thread_stack = thread_stack
 
-    def _add_task(self, task_name, func, callback, args, period_ms):
+    def _add_task(self, task_name, func, callback, args, period_ms, delay_ms):
         if task_name == None:
             self._uuid += 1
             task_name = str(self._uuid)
@@ -58,10 +65,18 @@ class EventLoop:
         _debug('callback', callback)
         _debug('args', args)
         _debug('period_ms', period_ms)
-        new_task = EventTask(func, callback, args, period_ms)
+        _debug('delay_ms', delay_ms)
+        new_task = EventTask(func, callback, args, period_ms, delay_ms)
         self._tasks[task_name] = new_task
 
-    def start_new_task(self, func, args, is_periodic=True, period_ms=1000, callback=None, task_name=None):
+    def start_new_task(self,
+                       func, args,
+                       is_periodic=True,
+                       period_ms=1000,
+                       callback=None,
+                       task_name=None,
+                       delay_ms=None
+                       ):
         """
         Add a task to EventLoop
         :param task_name: name of task
@@ -71,11 +86,16 @@ class EventLoop:
         :param args: arguments of func
         """
         if is_periodic:
-            self._add_task(task_name, func, callback, args, period_ms)
+            self._add_task(task_name, func, callback,
+                           args, period_ms, delay_ms)
         else:
-            self._add_task(task_name, func, callback, args, None)
+            self._add_task(task_name, func, callback, args, None, delay_ms)
 
-    def start_new_task_once(self, func, args, callback=None, task_name=None):
+    def start_new_task_once(self,
+                            func, args,
+                            callback=None,
+                            task_name=None,
+                            delay_ms=None):
         """
         Add a task to EventLoop, run once
         :param task_name: name of task
@@ -83,9 +103,10 @@ class EventLoop:
         :param callback: callback function
         :param args: arguments of func
         """
-        self.start_new_task(func, args, False, None, callback, task_name)
+        self.start_new_task(func, args, False, None,
+                            callback, task_name, delay_ms)
 
-    def start_new_task_periodic(self, func, args, period_ms=1000, callback=None, task_name=None):
+    def start_new_task_periodic(self, func, args, period_ms=1000, callback=None, task_name=None, delay_ms=None):
         """
         Add a task to EventLoop, run periodically
         :param task_name: name of task
@@ -94,7 +115,8 @@ class EventLoop:
         :param callback: callback function
         :param args: arguments of func
         """
-        self.start_new_task(func, args, True, period_ms, callback, task_name)
+        self.start_new_task(func, args, True, period_ms,
+                            callback, task_name, delay_ms)
 
     def remove_task(self, task_name):
         """
@@ -112,13 +134,14 @@ class EventLoop:
         while not self._need_stop:
             tick = time.tick_ms()
             for task_name, task in self._tasks.items():
-                if task._is_periodic:
-                    if tick - task._last_call_time > task._period_ms:
-                        self._run_task(task)
-                        task._last_call_time = tick
-                else:
+                if tick - task._last_call_time > task._period_ms:
+                    _debug('run_task', task_name)
+                    _debug('tick', tick)
+                    _debug('last_call_time', task._last_call_time)
                     self._run_task(task)
-                    self.remove_task(task_name)
+                    task._last_call_time = tick
+                    if not task._is_periodic:
+                        self.remove_task(task_name)
             if self._need_stop:
                 break
             time.sleep_ms(self._period_ms)
@@ -171,7 +194,13 @@ def _get_default_event_loop():
     return g_default_event_loop
 
 
-def start_new_task(func, args, is_periodic=True, period_ms=1000, callback=None, task_name=None):
+def start_new_task(func, args,
+                   is_periodic=True,
+                   period_ms=1000,
+                   callback=None,
+                   task_name=None,
+                   delay_ms=None
+                   ):
     """
     Add a task to EventLoop
     :param task_name: name of task
@@ -182,10 +211,14 @@ def start_new_task(func, args, is_periodic=True, period_ms=1000, callback=None,
     """
     eventloop = _get_default_event_loop()
     eventloop.start_new_task(func, args, is_periodic,
-                             period_ms, callback, task_name)
+                             period_ms, callback, task_name, delay_ms)
 
 
-def start_new_task_once(func, args, callback=None, task_name=None):
+def start_new_task_once(func, args,
+                        callback=None,
+                        task_name=None,
+                        delay_ms=None
+                        ):
     """
     Add a task to EventLoop, run once
     :param task_name: name of task
@@ -194,10 +227,15 @@ def start_new_task_once(func, args, callback=None, task_name=None):
     :param args: arguments of func
     """
     eventloop = _get_default_event_loop()
-    eventloop.start_new_task_once(func, args, callback, task_name)
+    eventloop.start_new_task_once(func, args, callback, task_name, delay_ms)
 
 
-def start_new_task_periodic(func, args, period_ms=1000, callback=None, task_name=None):
+def start_new_task_periodic(func, args,
+                            period_ms=1000,
+                            callback=None,
+                            task_name=None,
+                            delay_ms=None
+                            ):
     """
     Add a task to EventLoop, run periodically
     :param task_name: name of task
@@ -208,7 +246,7 @@ def start_new_task_periodic(func, args, period_ms=1000, callback=None, task_name
     """
     eventloop = _get_default_event_loop()
     eventloop.start_new_task_periodic(
-        func, args, period_ms, callback, task_name)
+        func, args, period_ms, callback, task_name, delay_ms)
 
 
 def remove_task(task_name):

+ 1 - 0
port/linux/package/pikascript/pikascript-lib/eventloop/README.md

@@ -0,0 +1 @@
+# eventloop

+ 5 - 5
src/PikaObj.c

@@ -55,9 +55,9 @@ PikaObj* New_PikaStdData_Dict(Args* args);
 PikaObj* New_PikaStdData_dict_keys(Args* args);
 PikaObj* New_PikaStdData_List(Args* args);
 PikaObj* New_PikaStdData_Tuple(Args* args);
-void PikaStdData_Tuple___init__(PikaObj *self);
-void PikaStdData_List___init__(PikaObj *self);
-void PikaStdData_List_append(PikaObj *self, Arg* arg);
+void PikaStdData_Tuple___init__(PikaObj* self);
+void PikaStdData_List___init__(PikaObj* self);
+void PikaStdData_List_append(PikaObj* self, Arg* arg);
 void _mem_cache_deinit(void);
 void _VMEvent_deinit(void);
 void pikaGC_markObj(PikaGC* gc, PikaObj* self);
@@ -2471,8 +2471,8 @@ void pks_printVersion(void) {
 }
 
 void pks_getVersion(char* buff) {
-    pika_sprintf(buff, "%d.%d.%d", PIKA_VERSION_MAJOR,
-                          PIKA_VERSION_MINOR, PIKA_VERSION_MICRO);
+    pika_sprintf(buff, "%d.%d.%d", PIKA_VERSION_MAJOR, PIKA_VERSION_MINOR,
+                 PIKA_VERSION_MICRO);
 }
 
 void* obj_getStruct(PikaObj* self, char* name) {

+ 9 - 0
test/VM-test.cpp

@@ -2820,6 +2820,15 @@ TEST_SINGLE_FILE(vm, issue_star_dict, "test/python/issue/issue_star_dict.py")
 
 TEST_SINGLE_FILE_PASS(vm, proxy2, "test/python/proxy/proxy2.py")
 
+#if 0  //! need fix
+TEST_RUN_LINES_PASS(vm,
+                    none_none,
+                    "assert (None is not None) == False\n"
+                    "print('PASS')\n")
+#endif
+
+TEST_RUN_LINES(vm, minus_none, "10 - None")
+
 #endif
 
 TEST_END

+ 43 - 0
test/python/eventloop/delay1.py

@@ -0,0 +1,43 @@
+import time
+from eventloop import EventLoop
+
+run_time = 0
+
+eventloop.set_debug(True)
+
+
+def test_func(arg1, arg2):
+    global run_time
+    run_time += 1
+    print("Running test function with arguments:", arg1, arg2)
+    return arg1 + arg2
+
+
+def test_func2(arg1, arg2):
+    print("test function 2 with arguments:", arg1, arg2)
+    return arg1 + arg2
+
+
+def test_callback(res):
+    print("Running test callback function", res)
+    assert res == "Hello World"
+
+
+# Test case 2: Add and run a periodic task
+
+eventloop.start_new_task_once(
+    test_func, ("Hello", " World"),
+    callback=test_callback,
+    delay_ms=2000
+)
+
+eventloop.start_new_task(
+    test_func2, ("Hello", " World"),
+    is_periodic=True,
+    period_ms=200,
+    callback=test_callback
+)
+
+# Sleep for enough time to allow the periodic task to run multiple times
+while run_time < 1:
+    time.sleep(0.1)

+ 9 - 0
test/test_common.h

@@ -65,6 +65,15 @@ extern char log_buff[LOG_BUFF_MAX][LOG_SIZE];
     EXPECT_EQ(pikaMemNow(), 0);                                                \
   }
 
+#define TEST_RUN_LINES_PASS(_test_suite_, _test_name_, _lines_)                \
+  TEST(_test_suite_, _test_name_) {                                            \
+    PikaObj *self = newRootObj("root", New_PikaStdLib_SysObj);                 \
+    obj_run(self, (_lines_)); /* collect */ /* assert */                       \
+    EXPECT_STREQ(log_buff[0], "PASS\r\n");                                     \
+    obj_deinit(self);                                                          \
+    EXPECT_EQ(pikaMemNow(), 0);                                                \
+  }
+
 #if USE_GOOGLE_TEST
 #include "gtest/gtest.h"
 #define TEST_START

+ 1 - 0
test/thread-test.cpp

@@ -38,6 +38,7 @@ TEST_SINGLE_FILE(thread, test2, "test/python/_thread/test2.py")
 TEST_SINGLE_FILE(eventloop, test1, "test/python/eventloop/test1.py")
 TEST_SINGLE_FILE(eventloop, test2, "test/python/eventloop/test2.py")
 TEST_SINGLE_FILE(eventloop, test3, "test/python/eventloop/test3.py")
+TEST_SINGLE_FILE(eventloop, delay1, "test/python/eventloop/delay1.py")
 
 #endif
 TEST_END