How to schedule a function to operate as a background task - python-3.x

Apologies for my poor phrasing but here goes.
I need to execute a function every thirty minutes whilst other tasks are running however I have no idea how to do this or to phrase it into google. My goal is to modify my script so that it operates (without a UI) like the task manager program with background services, programs, utils, ect.
I have tried to create this by timing each function and creating functions that execute other functions however no matter what I try it operates in an asynchronous fashion like any script would.
An example of this would include the following.
def function_1():
"""Perform operations"""
pass
def function_2():
"""Perform operations"""
pass
def executeAllFunctions():
function_1()
function_2()
How can I initialize function_1 as a background task whilst function_2 is executed in a normal manner?

There is an excellent answer here.
The main idea is to run an async coroutine in a forever loop inside a thread.
In your case, you have to define function one as a coroutine use a caller function to be in the thread and create a thread.
Sample example heavily inspired to the answer in the link but adapted to your question.
#asyncio.coroutine
def function_1():
while True:
do_stuff
yield from asyncio.sleep(1800)
def wrapper(loop):
asyncio.set_event_loop(loop)
loop.run_until_complete(function_1())
def function_2():
do_stuff
def launch():
loop = asyncio.get_event_loop()
t = threading.Thread(target=wrapper, args=(loop,)) # create the thread
t.start() # launch the thread
function_2()
t.exit() # when function_2 return

Related

How can I sleep() parallely inside asyncio task if parent function isn't async?

CODE:
class App:
def __init__(self):
# some of the code
...
...
xxx.add_handler(self.event_handler, event_xyz)
asyncio.create_task(self.keep_alive())
xxx.run_until_disconnected()
def keep_alive(self):
# stuff to keep connection alive
...
...
time.sleep(5) # this will block whole script
asyncio.sleep(5) # this won't work because of lack of async on _init_ and keep_alive
async def event_handler(self):
await stuff
# other functions
if __name__ == '__main__':
App()
The part of the code that keeps the connection alive has api limits. So, I need to have the sleep statement inside keep_alive() function.
I understand that the design of the code can be completely changed to make it work but it is a big script and everything else is working perfectly. So, preferable is if this could be made to work.
I'm open to using anything else like threads as long as rest of the code isn't getting blocked during the sleep.
This is a straightforward situation. time.sleep will block the current thread, including the asyncio event loop for that thread (if there is one). Period. Case closed.
If your API requires you to have time.sleep calls, and your program must do something while the current thread is sleeping, then asyncio is not the solution. That doesn't mean that asyncio cannot be used for other threads or other purposes within your program design, but it absolutely can't run other tasks in the current thread during a time.sleep interval.
Regarding the function keep_alive in your code snippet: this function cannot be made into a task because it's not declared as "async def." Calling asyncio.sleep() from inside this type of regular function is an error; it must always be "awaited," and the "await" keyword must be inside an async def function. On the other hand, calling time.sleep inside an async def function is not an error and the function will work as expected. But it's probably not something you want to do.

Is it possible to interrupt the main thread using child thread?

I have a function that will compute something then put it on a PDF. However, this process takes time. Because of this, we implement stop button for the user to stop the process.
I tried using thread.Event(), but the function I am working with is a non-looping function. This means that, I can't regularly check if event is set. (Hard coding the application by simply putting multiple checker will do but nope -- that idea is not accepted).
def generate_data(self, event):
self.thread = threading.Thread(target=self.check_event)
self.thread.start()
...
def check_event(self):
while True:
if self.event.is_set():
self.controller.enable_run_btn_and_tab()
return
time.sleep(1)
My idea is to create another thread that will regularly check if event is set so I can return and exit the function. However, the above code for def check_event(self) will only exit the child thread, not the thread for generate_date(self).
Is there some code or modification in my code to stop the main thread using child thread?

Python asyncio: starting a loop without created task

Could somebody explain me why I can't execute my tasks if I start the loop without any added tasks before? (Python 3.7)
import asyncio
import threading
def run_forever(loop):
loop.run_forever()
async def f(x):
print("%s executed" % x)
# init is called first
def init():
print("init started")
loop = asyncio.new_event_loop()
# loop.create_task(f("a1")) # <--- first commented task
thread = threading.Thread(target=run_forever, args=(loop,))
thread.start()
loop.create_task(f("a2")) # <--- this is not being executed
print("init finished")
If I leave comment on # loop.create_task(f("a1")) the execution is:
init started
init finished
Uncommented execution is:
init started
init finished
a1 executed
a2 executed
Why so? I wanted to create a loop and to add tasks in the future.
Unless explicitly stated otherwise, asyncio API is not thread-safe. This means that calling loop.create_task() from a thread other than the one that runs the event loop will not properly synchronize with the loop.
To submit the task to the event loop from a foreign thread, you need to invoke asyncio.run_coroutine_threadsafe instead:
asyncio.run_coroutine_threadsafe(f("a2"), loop)
This will wake up the loop to alert it that a new task has arrived, and it also returns a concurrent.futures.Future which you can use to obtain the result of the coroutine.

Scheduling actions

I'm making a BlackJack application using Kivy, I basically need to make a sort of delay or even a time.sleep, but of course, it doesn't have to freeze the program. I saw kivy has Clock.whatever to schedule certain actions. What I'd like to do is scheduling multiple actions so that when the first action has finished, the second will be run and so on. What's the best way to achive this? or is there in the Clock module something to perform multiple delays one after another?
This could be an example of what i need to do:
from kivy.clock import Clock
from kivy.uix import BoxLayout
from functools import partial
class Foo(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
for index_time, card in enumerate(cards, 1):
# Schedule this action to be run after 1 sec from the previous one and so on
Clock.schedule_once(partial(self.function, card), index_time)
def function(self, card, *args):
self.add_widget(card)
First, I'm surprised that your question didn't get down-voted since this is not supposed to be a place for opinion questions. So you shouldn't ask for best.
The Clock module doesn't have a specific method to do what you want. Obvioulsy, you could do a list of Clock.schedule_once() calls, as your example code does. Another way is to have each function schedule its successor, but that assumes that the functions will always be called in that order.
Anyway, there are many ways to do what you want. I have used a construct like the following:
class MyScheduler(Thread):
def __init__(self, funcsList=None, argsList=None, delaysList=None):
super(MyScheduler, self).__init__()
self.funcs = funcsList
self.delays = delaysList
self.args = argsList
def run(self):
theLock = threading.Lock()
for i in range(len(self.funcs)):
sleep(self.delays[i])
Clock.schedule_once(partial(self.funcs[i], *self.args[i], theLock))
theLock.acquire()
It is a separate thread, so you don't have to worry about freezing your gui. You pass it a list of functions to be executed, a list of arguments for those functions, and a list of delays (for a sleep before each function is executed). Note that using Clock.schedule_once() schedules the execution on the main thread, and not all functions need to be executed on the main thread. The functions must allow for an argument that is a Lock object and the functions must release the Lock when it completes. Something like:
def function2(self, card1, card2, theLock=None, *args):
print('in function2, card1 = ' + str(card1) + ', card2 = ' + str(card2))
if theLock is not None:
theLock.release()
The MyScheduler class __init__() method could use more checking to make sure it won't throw an exception when it is run.

Python thread never starts if run() contains yield from

Python 3.4, I'm trying to make a server using the websockets module (I was previously using regular sockets but wanted to make a javascript client) when I ran into an issue (because it expects async, at least if the examples are to be trusted, which I didn't use before). Threading simply does not work. If I run the following code, bar will never be printed, whereas if I comment out the line with yield from, it works as expected. So yield is probably doing something I don't quite understand, but why is it never even executed? Should I install python 3.5?
import threading
class SampleThread(threading.Thread):
def __init__(self):
super(SampleThread, self).__init__()
print("foo")
def run(self):
print("bar")
yield from var2
thread = SampleThread()
thread.start()
This is not the correct way to handle multithreading. run is neither a generator nor a coroutine. It should be noted that the asyncio event loop is only defined for the main thread. Any call to asyncio.get_event_loop() in a new thread (without first setting it with asyncio.set_event_loop() will throw an exception.
Before looking at running the event loop in a new thread, you should first analyze to see if you really need the event loop running in its own thread. It has a built-in thread pool executor at: loop.run_in_executor(). This will take a pool from concurrent.futures (either a ThreadPoolExecutor or a ProcessPoolExecutor) and provides a non-blocking way of running processes and threads directly from the loop object. As such, these can be await-ed (with Python3.5 syntax)
That being said, if you want to run your event loop from another thread, you can do it thustly:
import asyncio
class LoopThread(threading.Thread):
def __init__(self):
self.loop = asyncio.new_event_loop()
def run():
ayncio.set_event_loop(self.loop)
self.loop.run_forever()
def stop():
self.loop.call_soon_threadsafe(self.loop.stop)
From here, you still need to device a thread-safe way of creating tasks, etc. Some of the code in this thread is usable, although I did not have a lot of success with it: python asyncio, how to create and cancel tasks from another thread

Resources