I have two funtions, one runs increasing by one a number, and the other needs to capture the number that is running the first function every 5 seconds, so that when I capture the first number is 0, the sencond one is 10, the next one is 15, and so on... this is simulating the first function as a sensor. My code is as follows:
import time
import threading
from threading import Thread
def numero(i=0):
while True:
i = i + 1
time.sleep(1)
#print i
def capturar():
while True:
posicion = numero()
time.sleep(5)
print posicion
if __name__ == '__main__':
Thread(target = capturar()).start()
Thread(target = numero()).start()
When I run this code, it keeps in the first function, how can I get this run correctly and obtain the capture of the series of numbers every 5 seconds?
There are several mistakes in your code:
i is not in scope for capturar
you execute capturar and numero instead of handing the functions themselves to Thread
As Matt Clark commented, you call numero from capturar, which never returns, so capturar can't even do one full loop.
To help with the first one, the easiest solution is to wrap the functions into a class, and make i into an instance state (as an attribute). The second one merely requires you to remove the extra parentheses. The third one is resolved with the first one, as there is no function call required any more to fetch the counter state.
This should do what you want:
import time
from threading import Thread
class Contador:
def __init__(self, comienzo = 0):
self.numero = comienzo
def producir(self):
while True:
self.numero += 1
time.sleep(1)
def capturar(self):
while True:
posicion = self.numero
time.sleep(5)
print posicion
if __name__ == '__main__':
c = Contador()
Thread(target = c.capturar).start()
Thread(target = c.producir).start()
Thank you Amadan, the soution that you share is working perfectlym but when I tried to pull it into the real sensor (GPS), I am getting only "0"
import gps
import itertools
import json
import os
import portdetect
import time
import serial
from threading import Thread
(puerto1, puerto2) = portdetect.detectar_puerto()
print puerto1, puerto2
port = serial.Serial(puerto1, 115200, timeout=1)
os.system('sudo systemctl stop gpsd.socket')
time.sleep(2)
os.system('sudo systemctl disable gpsd.socket')
time.sleep(2)
comando = 'sudo gpsd ' + puerto2 + ' -F /var/run/gpsd.sock'
os.system(str(comando))
#print str(comando)
# Listen on port 2947 (gpsd) of localhost
session = gps.gps("localhost", "2947")
session.stream(gps.WATCH_ENABLE | gps.WATCH_NEWSTYLE)
class Contador:
def __init__(self, comienzo = 0):
self.raw_datos = comienzo
def leergps(self):
while True:
try:
report = session.next()
# Wait for a 'TPV' report and display the current time
# To see all report data, uncomment the line below
# print report
if report['class'] == 'TPV':
if hasattr(report, 'time') or hasattr(report, 'lat') or hasattr(report, 'lon') or hasattr(report,
'speed'):
datos = [report.time, report.lat, report.lon, report.speed]
clave = ['tiempo', 'lat', 'lon', 'speed']
diccionario = dict(itertools.izip(clave, datos))
self.raw_datos = (json.dumps(diccionario))
# print raw_datos
return self.raw_datos
else:
return report['class']
except:
print "Error de coordenadas"
def capturar(self):
while True:
posicion = self.raw_datos
time.sleep(5)
print posicion
if __name__ == '__main__':
c = Contador()
Thread(target = c.capturar).start()
Thread(target = c.leergps()).start()
I am trying only to pull the "raw data obtained every 5 seconds, but I am not achieving this"
Related
I'm writing a Python module to read jstest output and make Xbox gamepad working in Python on Linux. I need to start in background infinite while loop in __init__ on another thread that looks like this:
import os
from threading import Thread
import time
import select
import subprocess
class Joystick:
"""Initializes base class and launches jstest and xboxdrv"""
def __init__(self, refreshRate=2000, deadzone=4000):
self.proc = subprocess.Popen(['xboxdrv', '-D', '-v', '--detach-kernel-driver', '--dpad-as-button'], stdout=subprocess.PIPE, bufsize=0)
self.pipe = self.proc.stdout
self.refresh = refreshRate
self.refreshDelay = 1.0 / refreshRate
self.refreshTime = 0 # indicates the next refresh
self.deadzone = deadzone
self.start()
self.xbox = subprocess.Popen(['jstest', '--normal', '/dev/input/js0'], stdout=subprocess.PIPE, bufsize=-1, universal_newlines=True)
self.response = self.xbox.stdout.readline()
a = Thread(target=self.reload2())
a.start()
print("working")
def reload2(self):
while True:
self.response = self.xbox.stdout.readline()
print("read")
time.sleep(0.5)
def start(self):
global leftVibrateAmount, rightVibrateAmount
leftVibrateAmount = 0
rightVibrateAmount = 0
readTime = time.time() + 1 # here we wait a while
found = False
while readTime > time.time() and not found:
readable, writeable, exception = select.select([self.pipe], [], [], 0)
if readable:
response = self.pipe.readline()
# tries to detect if controller is connected
if response == b'[ERROR] XboxdrvDaemon::run(): fatal exception: DBusSubsystem::request_name(): failed to become primary owner of dbus name\n':
raise IOError("Another instance of xboxdrv is running.")
elif response == b'[INFO] XboxdrvDaemon::connect(): connecting slot to thread\n':
found = True
self.reading = response
elif response == b'':
raise IOError('Are you running as sudo?')
if not found:
self.pipe.close()
# halt if controller not found
raise IOError("Xbox controller/receiver isn't connected")
The loop is defined to start running in __init__ function like so:
a = threading.Thread(target=self.reload2) # code hangs here
a.start()
But each time I create variable "a", whole program hangs in while loop, which should be running in another thread.
Thanks for help.
You may be having issues with your __init__. I put it in a simple class as an example, and it runs as expected.
import time
from threading import Thread
class InfiniteLooper():
def __init__(self):
a = Thread(target=self.reload2) # reload, not reload(), otherwise you're executing reload2 and assigning the result to Target, but it's an infinite loop, so...
print('Added thread')
a.start()
print('Thread started')
def reload2(self):
while True:
self.response = input('Enter something')
print('read')
time.sleep(0.5)
loop = InfiniteLooper()
Output:
Added thread
Thread started
Enter something
1
read
Enter something
1
read
As you can see, the "Enter something" appears after I've added the thread and started it. It also loops fine
I've searched StackOverflow and although I've found many questions on this, I haven't found an answer that fits for my situation/not a strong python programmer to adapt their answer to fit my need.
I've looked here to no avail:
kill a function after a certain time in windows
Python: kill or terminate subprocess when timeout
signal.alarm replacement in Windows [Python]
I am using multiprocessing to run multiple SAP windows at once to pull reports. The is set up to run on a schedule every 5 minutes. Every once in a while, one of the reports gets stalled due to the GUI interface and never ends. I don't get an error or exception, it just stalls forever. What I would like is to have a timeout function that during this part of the code that is executed in SAP, if it takes longer than 4 minutes, it times out, closes SAP, skips the rest of the code, and waits for next scheduled report time.
I am using Windows Python 2.7
import multiprocessing
from multiprocessing import Manager, Process
import time
import datetime
### OPEN SAP ###
def start_SAP():
print 'opening SAP program'
### REPORTS IN SAP ###
def report_1(q, lock):
while True: # logic to get shared queue
if not q.empty():
lock.acquire()
k = q.get()
time.sleep(1)
lock.release()
break
else:
time.sleep(1)
print 'running report 1'
def report_2(q, lock):
while True: # logic to get shared queue
if not q.empty():
lock.acquire()
k = q.get()
time.sleep(1)
lock.release()
break
else:
time.sleep(1)
print 'running report 2'
def report_3(q, lock):
while True: # logic to get shared queue
if not q.empty():
lock.acquire()
k = q.get()
time.sleep(1)
lock.release()
break
else:
time.sleep(1)
time.sleep(60000) #mimicking the stall for report 3 that takes longer than allotted time
print 'running report 3'
def report_N(q, lock):
while True: # logic to get shared queue
if not q.empty():
lock.acquire()
k = q.get()
time.sleep(1)
lock.release()
break
else:
time.sleep(1)
print 'running report N'
### CLOSES SAP ###
def close_SAP():
print 'closes SAP'
def format_file():
print 'formatting files'
def multi_daily_pull():
lock = multiprocessing.Lock() # creating a lock in multiprocessing
shared_list = range(6) # creating a shared list for all functions to use
q = multiprocessing.Queue() # creating an empty queue in mulitprocessing
for n in shared_list: # putting list into the queue
q.put(n)
print 'Starting process at ', time.strftime('%m/%d/%Y %H:%M:%S')
print 'Starting SAP Pulls at ', time.strftime('%m/%d/%Y %H:%M:%S')
StartSAP = Process(target=start_SAP)
StartSAP.start()
StartSAP.join()
report1= Process(target=report_1, args=(q, lock))
report2= Process(target=report_2, args=(q, lock))
report3= Process(target=report_3, args=(q, lock))
reportN= Process(target=report_N, args=(q, lock))
report1.start()
report2.start()
report3.start()
reportN.start()
report1.join()
report2.join()
report3.join()
reportN.join()
EndSAP = Process(target=close_SAP)
EndSAP.start()
EndSAP.join()
formatfile = Process(target=format_file)
formatfile .start()
formatfile .join()
if __name__ == '__main__':
multi_daily_pull()
One way to do what you want would be to use the optional timeout argument that the Process.join() method accepts. This will make it only block the calling thread at most that length of time.
I also set the daemon attribute of each Process instance so your main thread will be able to terminate even if one of the processes it started is still "running" (or has hung up).
One final point, you don't need a multiprocessing.Lock to control access a multiprocessing.Queue, because they handle that aspect of things automatically, so I removed it. You may still want to have one for some other reason, such as controlling access to stdout so printing to it from the various processes doesn't overlap and mess up what is output to the screen.
import multiprocessing
from multiprocessing import Process
import time
import datetime
def start_SAP():
print 'opening SAP program'
### REPORTS IN SAP ###
def report_1(q):
while True: # logic to get shared queue
if q.empty():
time.sleep(1)
else:
k = q.get()
time.sleep(1)
break
print 'report 1 finished'
def report_2(q):
while True: # logic to get shared queue
if q.empty():
time.sleep(1)
else:
k = q.get()
time.sleep(1)
break
print 'report 2 finished'
def report_3(q):
while True: # logic to get shared queue
if q.empty():
time.sleep(1)
else:
k = q.get()
time.sleep(60000) # Take longer than allotted time
break
print 'report 3 finished'
def report_N(q):
while True: # logic to get shared queue
if q.empty():
time.sleep(1)
else:
k = q.get()
time.sleep(1)
break
print 'report N finished'
def close_SAP():
print 'closing SAP'
def format_file():
print 'formatting files'
def multi_daily_pull():
shared_list = range(6) # creating a shared list for all functions to use
q = multiprocessing.Queue() # creating an empty queue in mulitprocessing
for n in shared_list: # putting list into the queue
q.put(n)
print 'Starting process at ', time.strftime('%m/%d/%Y %H:%M:%S')
print 'Starting SAP Pulls at ', time.strftime('%m/%d/%Y %H:%M:%S')
StartSAP = Process(target=start_SAP)
StartSAP.start()
StartSAP.join()
report1 = Process(target=report_1, args=(q,))
report1.daemon = True
report2 = Process(target=report_2, args=(q,))
report2.daemon = True
report3 = Process(target=report_3, args=(q,))
report3.daemon = True
reportN = Process(target=report_N, args=(q,))
reportN.daemon = True
report1.start()
report2.start()
report3.start()
reportN.start()
report1.join(30)
report2.join(30)
report3.join(30)
reportN.join(30)
EndSAP = Process(target=close_SAP)
EndSAP.start()
EndSAP.join()
formatfile = Process(target=format_file)
formatfile .start()
formatfile .join()
if __name__ == '__main__':
multi_daily_pull()
This is pretty much what I have right now:
import time
import sys
done = 'false'
#here is the animation
def animate():
while done == 'false':
sys.stdout.write('\rloading |')
time.sleep(0.1)
sys.stdout.write('\rloading /')
time.sleep(0.1)
sys.stdout.write('\rloading -')
time.sleep(0.1)
sys.stdout.write('\rloading \\')
time.sleep(0.1)
sys.stdout.write('\rDone! ')
animate()
#long process here
done = 'false'
and I want to get it so that the "while" script would function independently, and it continues to the process, while the animation is going on until the end of the process signals the variable "done" to be 'false', stopping the animation and replacing it with "Done!". This method would be essentially running two scripts at once; is there a way to do it?
Use a thread:
import itertools
import threading
import time
import sys
done = False
#here is the animation
def animate():
for c in itertools.cycle(['|', '/', '-', '\\']):
if done:
break
sys.stdout.write('\rloading ' + c)
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write('\rDone! ')
t = threading.Thread(target=animate)
t.start()
#long process here
time.sleep(10)
done = True
I also made a couple of minor modifications to your animate() function, the only really important one was adding sys.stdout.flush() after the sys.stdout.write() calls.
Getting inspiration from the accepted answer, here's a useful class I wrote, printing a loader à la nodejs cli:
from itertools import cycle
from shutil import get_terminal_size
from threading import Thread
from time import sleep
class Loader:
def __init__(self, desc="Loading...", end="Done!", timeout=0.1):
"""
A loader-like context manager
Args:
desc (str, optional): The loader's description. Defaults to "Loading...".
end (str, optional): Final print. Defaults to "Done!".
timeout (float, optional): Sleep time between prints. Defaults to 0.1.
"""
self.desc = desc
self.end = end
self.timeout = timeout
self._thread = Thread(target=self._animate, daemon=True)
self.steps = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"]
self.done = False
def start(self):
self._thread.start()
return self
def _animate(self):
for c in cycle(self.steps):
if self.done:
break
print(f"\r{self.desc} {c}", flush=True, end="")
sleep(self.timeout)
def __enter__(self):
self.start()
def stop(self):
self.done = True
cols = get_terminal_size((80, 20)).columns
print("\r" + " " * cols, end="", flush=True)
print(f"\r{self.end}", flush=True)
def __exit__(self, exc_type, exc_value, tb):
# handle exceptions with those variables ^
self.stop()
if __name__ == "__main__":
with Loader("Loading with context manager..."):
for i in range(10):
sleep(0.25)
loader = Loader("Loading with object...", "That was fast!", 0.05).start()
for i in range(10):
sleep(0.25)
loader.stop()
Also if you're willing to use an external library you might want to look into rich's console.status
from time import sleep
from rich.console import Console
console = Console()
tasks = [f"task {n}" for n in range(1, 11)]
with console.status("[bold green]Working on tasks...") as status:
while tasks:
task = tasks.pop(0)
sleep(1)
console.log(f"{task} complete")
I see this is a threading problem and not just an animated loading problem. Most the answers provided in this QA thread provides only a pseudocode and left the reader on their own.
Here is an answer I am trying to give using a working example of threading and animated loading.
The reader may modify in accordance to their needs.
Import python packages
import sys, time, threading
Define your process
# Here is an example of the process function:
def the_process_function():
n = 20
for i in range(n):
time.sleep(1)
sys.stdout.write('\r'+'loading... process '+str(i)+'/'+str(n)+' '+ '{:.2f}'.format(i/n*100)+'%')
sys.stdout.flush()
sys.stdout.write('\r'+'loading... finished \n')
Define your animated characters function
def animated_loading():
chars = "/—\|"
for char in chars:
sys.stdout.write('\r'+'loading...'+char)
time.sleep(.1)
sys.stdout.flush()
Define name dan target of your thread
the_process = threading.Thread(name='process', target=the_process_function)
Start the thread
the_process.start()
while the process is alive, call the animated_loading() function
while the_process.isAlive():
animated_loading()
The main steps are outlined in the commented out line.
Here is my code:
import time
import sys
print("Loading:")
#animation = ["10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"]
animation = ["[■□□□□□□□□□]","[■■□□□□□□□□]", "[■■■□□□□□□□]", "[■■■■□□□□□□]", "[■■■■■□□□□□]", "[■■■■■■□□□□]", "[■■■■■■■□□□]", "[■■■■■■■■□□]", "[■■■■■■■■■□]", "[■■■■■■■■■■]"]
for i in range(len(animation)):
time.sleep(0.2)
sys.stdout.write("\r" + animation[i % len(animation)])
sys.stdout.flush()
print("\n")
import sys, time, threading
def your_function_name() :
# do something here
def loadingAnimation(process) :
while process.isAlive() :
chars = "/—\|"
for char in chars:
sys.stdout.write('\r'+'loading '+char)
time.sleep(.1)
sys.stdout.flush()
loading_process = threading.Thread(target=your_function_name)
loading_process.start()
loadingAnimation(loading_process)
loading_process.join()
Try this one
import time
import sys
animation = "|/-\\"
for i in range(100):
time.sleep(0.1)
sys.stdout.write("\r" + animation[i % len(animation)])
sys.stdout.flush()
#do something
print("End!")
from time import sleep
k='#'
j=0
k='#'
def fixed_space(i,array):
g=(' '*len(str(len(array))))
g=g.replace(' ','',len(str(int(i))))
return g
def ani(i,array):
global k
#For accessing the global variables that are defined out of the function
global j
per=((i+1)*100)//len(array)
#To calculate percentage of completion of loop
c=per//5
#Integer division (the value 5 decides the length of the bar)
if c!=j:
#When ever the values of these 2 variables change add one # to the global variable k
k+='#'
y='['+k+' '+']'
#20 empty spaces (100/5)
y=y.replace(' ','',len(k))
#To make the size of the bar fixed ever time the length of k increases one ' ' will be removed
g=fixed_space(per,array)
#To fix at the same position
f=fixed_space(i,array)
print('Status : ',y,g+str(per)+'%',' ('+f+str(i+1)+' / '+str(len(array))+' ) ',end='\r')
#That same '\r' to clear previous text
j=c
array = range(100)
for i in array:
ani(i,array)
sleep(0.1)
my code is little bit messed up so feel free to update it
a simple one
from time import sleep #for delay
from itertools import cycle #for infinite cycling through a list
for i in cycle(["|", "/", "-", "\\"]):
print(i,end='\r') # '\r' clears the previous output
sleep(0.2)
Try it:
import threading, sys, time, webbrowser
def search_yt(inp_yt):
webbrowser.open(f"https://www.youtube.com/results?search_query={inp_yt}")
def loading(message="", round=1, _sleep=0.7, mark='-'):
no = round
hyphen = mark
space = ["", " ", " ", " ", " ", " ", " ", " ", " ", " "]
for loop in range(0, 10):
sys.stdout.write(f"\r{message} [{hyphen}{space[9 - loop]}]")
time.sleep(_sleep)
hyphen += mark
if no != 1:
loading(message, no -1 , _sleep, mark)
t1 = threading.Thread(target=loading, args=("hello",1, 0.5,"=",))#loading()
t2 = threading.Thread(target=search_yt, args=("python",))
t1.start()
t2.start()
Its all done with a few lines of code:
import time
import os
anime = ["|", "/", "-", "\\"]
done = False
while done is False:
for i in anime:
print('Please wait while system is Loading...', i)
os.system('clear')
time.sleep(0.1)
Tested and working successfully in the terminal.
I use a OneWire sensor (ds18b20) to read out a temperature and use it in a PI-algorithm to controll a SSR relay. I want to use a Pipe between the two functions to to send the temperature and make te "Reg" function to run as fast as possible. If I don't use a Pipe the Reg-function waits for the temperature-function (uses 0.75 seconds) and the output gets wrong...
Can anyone please show me how to use the Pipe function.??
The code:
import time
import RPi.GPIO as GPIO
import os
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(22, GPIO.OUT)
def temperatur(self):
while True:
tfile = open("/sys/bus/w1/devices/28-00000433f810/w1_slave")
text = tfile.read()
tfile.close()
secondline = text.split("\n")[1]
temperaturedata = secondline.split(" ")[9]
temp2 = float(temperaturedata[2:])
self.temp = temp2 / 1000
print self.temp
def reg(self):
while True:
ek = self.ref - self.temp
P_del = self.Kp * ek
I_del = ((self.Kp * self.Syklustid) / self.Ti) * ek
Paadrag = P_del + I_del
if Paadrag > 100:
Paadrag = 100
if Paadrag < 0:
Paadrag = 0
print "Paadrag: ", Paadrag, " Temperatur: ", self.temp
duty = Paadrag / 100.0
on_time = self.Syklustid * (duty)
off_time = self.Syklustid * (1.0-duty)
print "On_time: ", on_time, " Off_time: ", off_time
GPIO.output(22, GPIO.HIGH)
time.sleep(on_time)
GPIO.output(22, GPIO.LOW)
time.sleep(off_time
if __name__ == '__main__':
This is straight from the python documentation:
http://docs.python.org/2/library/multiprocessing.html
from multiprocessing import Process, Pipe
def f(conn):
conn.send([42, None, 'hello'])
conn.close()
if __name__ == '__main__':
parent_conn, child_conn = Pipe()
p = Process(target=f, args=(child_conn,))
p.start()
print parent_conn.recv() # prints "[42, None, 'hello']"
p.join()
I've had better results using shared state. Especially for simple data like temperature (a number I assume - not a complex custom object or whatever) Here is a wee example (again you will find more in the python docs)
#import stuff
from multiprocessing import Process, Manager
# Create a shared dictionary of paremeters for both processes to use
manager = Manager()
global_props = manager.dict()
# SuperImportant - initialise all parameters first!!
global_props.update({'temp': 21.3})
def functionOne(global_props):
# Do some stuff read temperature
global_props['temp'] = newVal
def functionTwo(global_props):
temp = global_props['temp']
# Do some stuff with the new value
# assign listeners to the two processes, passing in the properties dictionary
handlerOne = functionOne # This can also be a class in which case it calls __init__()
handlerTwo = functionTwo
processOne = Process(target=handlerOne,
args=(global_props))
processTwo = Process(target=handlerTwo,
args=(global_props))
# Start the processes running...
processOne.start()
processTwo.start()
processOne.join()
processTwo.join()
I've read a lot of posts about using threads, subprocesses, etc.. A lot of it seems over complicated for what I'm trying to do...
All I want to do is stop executing a function after X amount of time has elapsed.
def big_loop(bob):
x = bob
start = time.time()
while True:
print time.time()-start
This function is an endless loop that never throws any errors or exceptions, period.
I"m not sure the difference between "commands, shells, subprocesses, threads, etc.." and this function, which is why I'm having trouble manipulating subprocesses.
I found this code here, and tried it but as you can see it keeps printing after 10 seconds have elapsed:
import time
import threading
import subprocess as sub
import time
class RunCmd(threading.Thread):
def __init__(self, cmd, timeout):
threading.Thread.__init__(self)
self.cmd = cmd
self.timeout = timeout
def run(self):
self.p = sub.Popen(self.cmd)
self.p.wait()
def Run(self):
self.start()
self.join(self.timeout)
if self.is_alive():
self.p.terminate()
self.join()
def big_loop(bob):
x = bob
start = time.time()
while True:
print time.time()-start
RunCmd(big_loop('jimijojo'), 10).Run() #supposed to quit after 10 seconds, but doesn't
x = raw_input('DONEEEEEEEEEEEE')
What's a simple way this function can be killed. As you can see in my attempt above, it doesn't terminate after 20 seconds and just keeps on going...
***OH also, I've read about using signal, but I"m on windows so I can't use the alarm feature.. (python 2.7)
**assume the "infinitely running function" can't be manipulated or changed to be non-infinite, if I could change the function, well I'd just change it to be non infinite wouldn't I?
Here are some similar questions, which I haven't able to port over their code to work with my simple function:
Perhaps you can?
Python: kill or terminate subprocess when timeout
signal.alarm replacement in Windows [Python]
Ok I tried an answer I received, it works.. but how can I use it if I remove the if __name__ == "__main__": statement? When I remove this statement, the loop never ends as it did before..
import multiprocessing
import Queue
import time
def infinite_loop_function(bob):
var = bob
start = time.time()
while True:
time.sleep(1)
print time.time()-start
print 'this statement will never print'
def wrapper(queue, bob):
result = infinite_loop_function(bob)
queue.put(result)
queue.close()
#if __name__ == "__main__":
queue = multiprocessing.Queue(1) # Maximum size is 1
proc = multiprocessing.Process(target=wrapper, args=(queue, 'var'))
proc.start()
# Wait for TIMEOUT seconds
try:
timeout = 10
result = queue.get(True, timeout)
except Queue.Empty:
# Deal with lack of data somehow
result = None
finally:
proc.terminate()
print 'running other code, now that that infinite loop has been defeated!'
print 'bla bla bla'
x = raw_input('done')
Use the building blocks in the multiprocessing module:
import multiprocessing
import Queue
TIMEOUT = 5
def big_loop(bob):
import time
time.sleep(4)
return bob*2
def wrapper(queue, bob):
result = big_loop(bob)
queue.put(result)
queue.close()
def run_loop_with_timeout():
bob = 21 # Whatever sensible value you need
queue = multiprocessing.Queue(1) # Maximum size is 1
proc = multiprocessing.Process(target=wrapper, args=(queue, bob))
proc.start()
# Wait for TIMEOUT seconds
try:
result = queue.get(True, TIMEOUT)
except Queue.Empty:
# Deal with lack of data somehow
result = None
finally:
proc.terminate()
# Process data here, not in try block above, otherwise your process keeps running
print result
if __name__ == "__main__":
run_loop_with_timeout()
You could also accomplish this with a Pipe/Connection pair, but I'm not familiar with their API. Change the sleep time or TIMEOUT to check the behaviour for either case.
There is no straightforward way to kill a function after a certain amount of time without running the function in a separate process. A better approach would probably be to rewrite the function so that it returns after a specified time:
import time
def big_loop(bob, timeout):
x = bob
start = time.time()
end = start + timeout
while time.time() < end:
print time.time() - start
# Do more stuff here as needed
Can't you just return from the loop?
start = time.time()
endt = start + 30
while True:
now = time.time()
if now > endt:
return
else:
print end - start
import os,signal,time
cpid = os.fork()
if cpid == 0:
while True:
# do stuff
else:
time.sleep(10)
os.kill(cpid, signal.SIGKILL)
You can also check in the loop of a thread for an event, which is more portable and flexible as it allows other reactions than brute killing. However, this approach fails if # do stuff can take time (or even wait forever on some event).