Re: Data unchanged when passing data to Python in multiprocessing shared memory
> On 1 Feb 2022, at 23:40, Jen Kris wrote:
>
> Barry, thanks for your reply.
>
> On the theory that it is not yet possible to pass data from a non-Python
> language to Python with multiprocessing.shared_memory, I bypassed the problem
> by attaching 4 bytes to my FIFO pipe message from NASM to Python:
>
> byte_val = v[10:14]
>
> where v is the message read from the FIFO. Then:
>
> breakup = int.from_bytes(byte_val, "big")
> print("this is breakup " + str(breakup))
>
> Python prints: this is breakup 32894
>
> Note that I had to switch from little endian to big endian. Python is little
> endian by default, but in this case it's big endian.
>
> However, if anyone on this list knows how to pass data from a non-Python
> language to Python in multiprocessing.shared_memory please let me (and the
> list) know.
By using the struct module you can control for endian of the data.
Barry
>
> Thanks.
>
>
> Feb 1, 2022, 14:20 by [email protected]:
>
> On 1 Feb 2022, at 20:26, Jen Kris via Python-list
> wrote:
>
> I am using multiprocesssing.shared_memory to pass data between NASM and
> Python. The shared memory is created in NASM before Python is called. Python
> connects to the shm: shm_00 =
> shared_memory.SharedMemory(name='shm_object_00',create=False).
>
> I have used shared memory at other points in this project to pass text data
> from Python back to NASM with no problems. But now this time I need to pass a
> 32-bit integer (specifically 32,894) from NASM to Python.
>
> First I convert the integer to bytes in a C program linked into NASM:
>
> unsigned char bytes[4]
> unsigned long int_to_convert = 32894;
>
> bytes[0] = (int_to_convert >> 24) & 0xFF;
> bytes[1] = (int_to_convert >> 16) & 0xFF;
> bytes[2] = (int_to_convert >> 8) & 0xFF;
> bytes[3] = int_to_convert & 0xFF;
> memcpy(outbuf, bytes, 4);
>
> where outbuf is a pointer to the shared memory. On return from C to NASM, I
> verify that the first four bytes of the shared memory contain what I want,
> and they are 0, 0, -128, 126 which is binary 1000
> 0110, and that's correct (32,894).
>
> Next I send a message to Python through a FIFO to read the data from shared
> memory. Python uses the following code to read the first four bytes of the
> shared memory:
>
> byte_val = shm_00.buf[:4]
> print(shm_00.buf[0])
> print(shm_00.buf[1])
> print(shm_00.buf[2])
> print(shm_00.buf[3])
>
> But the bytes show as 40 39 96 96, which is exactly what the first four bytes
> of this shared memory contained before I called C to overwrite them with the
> bytes 0, 0, -128, 126. So Python does not see the updated bytes, and
> naturally int.from_bytes(byte_val, "little") does not return the result I
> want.
>
> I know that Python refers to shm00.buf, using the buffer protocol. Is that
> the reason that Python can't see the data that has been updated by another
> language?
>
> So my question is, how can I alter the data in shared memory in a non-Python
> language to pass back to Python?
>
> Maybe you need to use a memory barrier to force the data to be seen by
> another cpu?
> Maybe use shm lock operation to sync both sides?
> Googling I see people talking about using stdatomic.h for this.
>
> But I am far from clear what you would need to do.
>
> Barry
>
> Thanks,
>
> Jen
>
> --
> https://mail.python.org/mailman/listinfo/python-list
>
--
https://mail.python.org/mailman/listinfo/python-list
Why dict.setdefault() has value as optional?
Just out of curiosity: why dict.setdefault() has the default parameter that well, has a default value (None)? I used setdefault in the past, but I always specified a value. What's the use case of setting None by default? -- https://mail.python.org/mailman/listinfo/python-list
Re: Why dict.setdefault() has value as optional?
This is a quite philosophical queston if you look at it in general: "What value do you give a variable, that is not set?" You are right, at first it seems strange to have a default of None. But how do you want to signal that no default is set yet? Especially if you think of a dict that can have multiple keys with each different values of different types? Have fun in the rabbithole ;-) Cheers Lars Am 02.02.22 um 13:54 schrieb Marco Sulla: Just out of curiosity: why dict.setdefault() has the default parameter that well, has a default value (None)? I used setdefault in the past, but I always specified a value. What's the use case of setting None by default? -- punkt.de GmbH Lars Liedtke .infrastructure Kaiserallee 13a 76133 Karlsruhe Tel. +49 721 9109 500 https://infrastructure.punkt.de [email protected] AG Mannheim 108285 Geschäftsführer: Jürgen Egeling, Daniel Lienert, Fabian Stein -- https://mail.python.org/mailman/listinfo/python-list
Re: Data unchanged when passing data to Python in multiprocessing shared memory
On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris
declaimed the following:
>
> breakup = int.from_bytes(byte_val, "big")
>print("this is breakup " + str(breakup))
>
>Python prints: this is breakup 32894
>
>Note that I had to switch from little endian to big endian. Python is little
>endian by default, but in this case it's big endian.
>
Look at the struct module. I'm pretty certain it has flags for big or
little end, or system native (that, or run your integers through the
various "network byte order" functions that I think C and Python both
support.
https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html
>However, if anyone on this list knows how to pass data from a non-Python
>language to Python in multiprocessing.shared_memory please let me (and the
>list) know.
MMU cache lines not writing through to RAM? Can't find
anything on Google to force a cache flush Can you test on a
different OS? (Windows vs Linux)
--
Wulfraed Dennis Lee Bieber AF6VN
[email protected]://wlfraed.microdiversity.freeddns.org/
--
https://mail.python.org/mailman/listinfo/python-list
Re: Why dict.setdefault() has value as optional?
On Wed, 2 Feb 2022 at 14:34, Lars Liedtke wrote: > > This is a quite philosophical queston if you look at it in general: > "What value do you give a variable, that is not set?" Maybe I expressed my question badly. My existential doubt is why setdefault has an optional parameter for the value and not a required parameter. I'm not asking why the default is None. -- https://mail.python.org/mailman/listinfo/python-list
Re: http.client and dns lookups
Michael Welle wrote at 2022-2-1 19:28 +0100: > ... >That doesn't happen when the 'real' issue occurs. Attaching strace to >the Python process I can see that resolv.conf is stat'ed and open'ed. I >guess now I'm more confused than before ;). There must be an additional >condition that I'm missing. The DNS service routinely uses caches. Outdated cache values can cause (apparently non deterministic) failures. -- https://mail.python.org/mailman/listinfo/python-list
Re: Data unchanged when passing data to Python in multiprocessing shared memory
I applaud trying to find the right solution but wonder if a more trivial solution is even being considered. It ignores big and little endians and just converts your data into another form and back. If all you want to do is send an integer that fit in 32 bits or 64 bits, why not convert it to a character string in a form that both machines will see the same way and when read back, convert it back to an integer? As long as both side see the same string, this can be done in reasonable time and portably. Or am I missing something? Is "1234" not necessarily seen in the same order, or "1.234e3" or whatever? Obviously, if the mechanism is heavily used and multiple sides keep reading and even writing the same memory location, this is not ideal. But having different incompatible processors looking at the same memory is also not. -Original Message- From: Dennis Lee Bieber To: [email protected] Sent: Wed, Feb 2, 2022 12:30 am Subject: Re: Data unchanged when passing data to Python in multiprocessing shared memory On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris declaimed the following: > > breakup = int.from_bytes(byte_val, "big") >print("this is breakup " + str(breakup)) > >Python prints: this is breakup 32894 > >Note that I had to switch from little endian to big endian. Python is little >endian by default, but in this case it's big endian. > Look at the struct module. I'm pretty certain it has flags for big or little end, or system native (that, or run your integers through the various "network byte order" functions that I think C and Python both support. https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html >However, if anyone on this list knows how to pass data from a non-Python >language to Python in multiprocessing.shared_memory please let me (and the >list) know. MMU cache lines not writing through to RAM? Can't find anything on Google to force a cache flush Can you test on a different OS? (Windows vs Linux) -- Wulfraed Dennis Lee Bieber AF6VN [email protected] http://wlfraed.microdiversity.freeddns.org/ -- https://mail.python.org/mailman/listinfo/python-list -- https://mail.python.org/mailman/listinfo/python-list
Re: Data unchanged when passing data to Python in multiprocessing shared memory
It's not clear to me from the struct module whether it can actually auto-detect endianness. I think it must be specified, just as I had to do with int.from_bytes(). In my case endianness was dictated by how the four bytes were populated, starting with the zero bytes on the left. Feb 1, 2022, 21:30 by [email protected]: > On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris > declaimed the following: > >> >> breakup = int.from_bytes(byte_val, "big") >> > >print("this is breakup " + str(breakup)) > >> >> > >Python prints: this is breakup 32894 > >> >> > >Note that I had to switch from little endian to big endian. Python is > >little endian by default, but in this case it's big endian. > >> >> > Look at the struct module. I'm pretty certain it has flags for big or > little end, or system native (that, or run your integers through the > various "network byte order" functions that I think C and Python both > support. > > https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html > > > >However, if anyone on this list knows how to pass data from a non-Python > >language to Python in multiprocessing.shared_memory please let me (and the > >list) know. > > MMU cache lines not writing through to RAM? Can't find > anything on Google to force a cache flush Can you test on a > different OS? (Windows vs Linux) > > > > -- > Wulfraed Dennis Lee Bieber AF6VN > [email protected]://wlfraed.microdiversity.freeddns.org/ > -- > https://mail.python.org/mailman/listinfo/python-list > -- https://mail.python.org/mailman/listinfo/python-list
Re: Data unchanged when passing data to Python in multiprocessing shared memory
An ASCII string will not work. If you convert 32894 to an ascii string you will have five bytes, but you need four. In my original post I showed the C program I used to convert any 32-bit number to 4 bytes. Feb 2, 2022, 10:16 by [email protected]: > I applaud trying to find the right solution but wonder if a more trivial > solution is even being considered. It ignores big and little endians and just > converts your data into another form and back. > > If all you want to do is send an integer that fit in 32 bits or 64 bits, why > not convert it to a character string in a form that both machines will see > the same way and when read back, convert it back to an integer? > > As long as both side see the same string, this can be done in reasonable time > and portably. > > Or am I missing something? Is "1234" not necessarily seen in the same order, > or "1.234e3" or whatever? > > Obviously, if the mechanism is heavily used and multiple sides keep reading > and even writing the same memory location, this is not ideal. But having > different incompatible processors looking at the same memory is also not. > > -Original Message- > From: Dennis Lee Bieber > To: [email protected] > Sent: Wed, Feb 2, 2022 12:30 am > Subject: Re: Data unchanged when passing data to Python in multiprocessing > shared memory > > > On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris > > declaimed the following: > > > >> >> >> breakup = int.from_bytes(byte_val, "big") >> > > >print("this is breakup " + str(breakup)) > >> >> > > >Python prints: this is breakup 32894 > >> >> > > >Note that I had to switch from little endian to big endian. Python is > >little endian by default, but in this case it's big endian. > >> >> > > Look at the struct module. I'm pretty certain it has flags for big or > > little end, or system native (that, or run your integers through the > > various "network byte order" functions that I think C and Python both > > support. > > > > https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html > > > > > > >However, if anyone on this list knows how to pass data from a non-Python > >language to Python in multiprocessing.shared_memory please let me (and the > >list) know. > > > > MMU cache lines not writing through to RAM? Can't find > > anything on Google to force a cache flush Can you test on a > > different OS? (Windows vs Linux) > > > > > > > > -- > > Wulfraed Dennis Lee Bieber AF6VN > > [email protected] http://wlfraed.microdiversity.freeddns.org/ > > -- > > https://mail.python.org/mailman/listinfo/python-list > > -- > https://mail.python.org/mailman/listinfo/python-list > -- https://mail.python.org/mailman/listinfo/python-list
Re: Data unchanged when passing data to Python in multiprocessing shared memory
On Wed, 2 Feb 2022 19:16:19 +0100 (CET), Jen Kris declaimed the following: >It's not clear to me from the struct module whether it can actually >auto-detect endianness. I think it must be specified, just as I had to do >with int.from_bytes(). In my case endianness was dictated by how the four >bytes were populated, starting with the zero bytes on the left. Which is why I also suggested maybe looking at the various network/host translation calls. They are in the socket module of Python, and should also be available in most C standard libraries... https://docs.python.org/3/library/socket.html#other-functions """ socket.ntohl(x) Convert 32-bit positive integers from network to host byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 4-byte swap operation. socket.ntohs(x) Convert 16-bit positive integers from network to host byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 2-byte swap operation. Changed in version 3.10: Raises OverflowError if x does not fit in a 16-bit unsigned integer. socket.htonl(x) Convert 32-bit positive integers from host to network byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 4-byte swap operation. socket.htons(x) Convert 16-bit positive integers from host to network byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 2-byte swap operation. Changed in version 3.10: Raises OverflowError if x does not fit in a 16-bit unsigned integer. """ https://docs.python.org/3/library/struct.html """ Byte Order, Size, and Alignment By default, C types are represented in the machine’s native format and byte order, and properly aligned by skipping pad bytes if necessary (according to the rules used by the C compiler). Alternatively, the first character of the format string can be used to indicate the byte order, size and alignment of the packed data, according to the following table: Character Byte order SizeAlignment @ native native native = native standardnone < little-endian standardnone > big-endian standardnone ! network (= big-endian) << standardnone<< If the first character is not one of these, '@' is assumed. """ Since all the programs in your situation are running on the same machine, it would appear that at least one of them is NOT formatting integers in native host mode -- and I don't think it is Python. https://www.tutorialspoint.com/unix_sockets/network_byte_orders.htm """ These functions are macros and result in the insertion of conversion source code into the calling program. On little-endian machines, the code will change the values around to network byte order. On big-endian machines, no code is inserted since none is needed; the functions are defined as null. """ -- Wulfraed Dennis Lee Bieber AF6VN [email protected]://wlfraed.microdiversity.freeddns.org/ -- https://mail.python.org/mailman/listinfo/python-list
Waht do you think about my repeated_timer class
I need (sometimes) to repeatedly execute a function. For this I wrote
the below class. What do you think about it?
from threading import Timer
class repeated_timer(object):
def __init__(self, fn, interval, start = False):
if not callable(fn):
raise TypeError('{} is not a function'.format(fn))
self._fn = fn
self._check_interval(interval)
self._interval = interval
self._timer = None
self._is_running = False
if start:
self.start()
def _check_interval(self, interval):
if not type(interval) in [int, float]:
raise TypeError('{} is not numeric'.format(interval))
if interval <= 0:
raise ValueError('{} is not greater as 0'.format(interval))
def _next(self):
self._timer = Timer(self._interval, self._run)
self._timer.start()
def _run(self):
self._next()
self._fn()
def set_interval(self, interval):
self._check_interval(interval)
self._interval = interval
def start(self):
if not self._is_running:
self._next()
self._is_running = True
def stop(self):
if self._is_running:
self._timer.cancel()
self._timer = None
self._is_running = False
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
--
https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
You could add a __del__ that calls stop :)
On Wed, 2 Feb 2022 at 21:23, Cecil Westerhof via Python-list
wrote:
>
> I need (sometimes) to repeatedly execute a function. For this I wrote
> the below class. What do you think about it?
> from threading import Timer
>
>
>
> class repeated_timer(object):
> def __init__(self, fn, interval, start = False):
> if not callable(fn):
> raise TypeError('{} is not a function'.format(fn))
> self._fn = fn
> self._check_interval(interval)
> self._interval = interval
> self._timer = None
> self._is_running = False
> if start:
> self.start()
>
> def _check_interval(self, interval):
> if not type(interval) in [int, float]:
> raise TypeError('{} is not numeric'.format(interval))
> if interval <= 0:
> raise ValueError('{} is not greater as 0'.format(interval))
>
> def _next(self):
> self._timer = Timer(self._interval, self._run)
> self._timer.start()
>
> def _run(self):
> self._next()
> self._fn()
>
> def set_interval(self, interval):
> self._check_interval(interval)
> self._interval = interval
>
> def start(self):
> if not self._is_running:
> self._next()
> self._is_running = True
>
> def stop(self):
> if self._is_running:
> self._timer.cancel()
> self._timer = None
> self._is_running = False
>
> --
> Cecil Westerhof
> Senior Software Engineer
> LinkedIn: http://www.linkedin.com/in/cecilwesterhof
> --
> https://mail.python.org/mailman/listinfo/python-list
--
https://mail.python.org/mailman/listinfo/python-list
Re: Data unchanged when passing data to Python in multiprocessing shared memory
> On 2 Feb 2022, at 18:19, Jen Kris via Python-list > wrote: > > It's not clear to me from the struct module whether it can actually > auto-detect endianness. It is impossible to auto detect endian in the general case. > I think it must be specified, just as I had to do with int.from_bytes(). In > my case endianness was dictated by how the four bytes were populated, > starting with the zero bytes on the left. You can specify the endian explicitly in the format strings. It’s all in the docs. Barry > > > Feb 1, 2022, 21:30 by [email protected]: > >> On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris >> declaimed the following: >> >>> >>> breakup = int.from_bytes(byte_val, "big") >>> >>> print("this is breakup " + str(breakup)) >> >>> >>> >>> Python prints: this is breakup 32894 >> >>> >>> >>> Note that I had to switch from little endian to big endian. Python is >>> little endian by default, but in this case it's big endian. >> >>> >>> >> Look at the struct module. I'm pretty certain it has flags for big or >> little end, or system native (that, or run your integers through the >> various "network byte order" functions that I think C and Python both >> support. >> >> https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html >> >> >>> However, if anyone on this list knows how to pass data from a non-Python >>> language to Python in multiprocessing.shared_memory please let me (and the >>> list) know. >> >> MMU cache lines not writing through to RAM? Can't find >> anything on Google to force a cache flush Can you test on a >> different OS? (Windows vs Linux) >> >> >> >> -- >> Wulfraed Dennis Lee Bieber AF6VN >> [email protected]://wlfraed.microdiversity.freeddns.org/ >> -- >> https://mail.python.org/mailman/listinfo/python-list >> > > -- > https://mail.python.org/mailman/listinfo/python-list -- https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
> On 2 Feb 2022, at 21:12, Marco Sulla wrote:
>
> You could add a __del__ that calls stop :)
Didn’t python3 make this non deterministic when del is called?
I thought the recommendation is to not rely on __del__ in python3 code.
Barry
>
>> On Wed, 2 Feb 2022 at 21:23, Cecil Westerhof via Python-list
>> wrote:
>>
>> I need (sometimes) to repeatedly execute a function. For this I wrote
>> the below class. What do you think about it?
>>from threading import Timer
>>
>>
>>
>>class repeated_timer(object):
>>def __init__(self, fn, interval, start = False):
>>if not callable(fn):
>>raise TypeError('{} is not a function'.format(fn))
>>self._fn = fn
>>self._check_interval(interval)
>>self._interval = interval
>>self._timer = None
>>self._is_running = False
>>if start:
>>self.start()
>>
>>def _check_interval(self, interval):
>>if not type(interval) in [int, float]:
>>raise TypeError('{} is not numeric'.format(interval))
>>if interval <= 0:
>>raise ValueError('{} is not greater as 0'.format(interval))
>>
>>def _next(self):
>>self._timer = Timer(self._interval, self._run)
>>self._timer.start()
>>
>>def _run(self):
>>self._next()
>>self._fn()
>>
>>def set_interval(self, interval):
>>self._check_interval(interval)
>>self._interval = interval
>>
>>def start(self):
>>if not self._is_running:
>>self._next()
>>self._is_running = True
>>
>>def stop(self):
>>if self._is_running:
>>self._timer.cancel()
>>self._timer = None
>>self._is_running = False
>>
>> --
>> Cecil Westerhof
>> Senior Software Engineer
>> LinkedIn: http://www.linkedin.com/in/cecilwesterhof
>> --
>> https://mail.python.org/mailman/listinfo/python-list
> --
> https://mail.python.org/mailman/listinfo/python-list
>
--
https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
On Thu, 3 Feb 2022 at 09:33, Barry wrote: > > > > > On 2 Feb 2022, at 21:12, Marco Sulla wrote: > > > > You could add a __del__ that calls stop :) > > Didn’t python3 make this non deterministic when del is called? > > I thought the recommendation is to not rely on __del__ in python3 code. > The __del__ method is called when the object is being disposed of. Aside from some considerations about interpreter shutdown, it's perfectly reliable... as long as you understand that objects don't get disposed of when they "go out of scope", but when they run out of references and get garbage collected. So for instance, you can't depend on "x = Spam(); x = Ham()" to dispose of the Spam object instantly, because it might not get garbage collected instantly; but you can depend on __del__ getting called when the Spam object gets garbage collected. With that said, I can guarantee you that a __del__ method is NOT the right way to call stop, for one simple reason: the object will keep its own references (via the timer) so long as it is running. So it won't get garbage collected, and in fact, this is very important to it being reliable. Consider this simpler example: def call_soon(func): t = threading.Timer(10, func) t.start() When this function returns, you can no longer refer to the object 't'. Will the function be called at the appropriate time? Yes, it absolutely will, and it would be highly surprising if it didn't! So the thread itself keeps a reference to the important objects. (Side point: The OP's code is quite inefficient, as it creates a new thread for each reiteration, but there's nothing wrong with that if you're looking for something simple.) The main reason to "not rely on __del__" (and, by the way, that's nothing to do with whether it's Python 2 or Python 3, this has been true since early Py2 and possibly earlier) is that you don't know when the object will be disposed of. So if you want to guarantee that something is cleaned up, what you need is a way for the object itself to still exist, but the corresponding resource to be cleaned up. A classic example is a file object: def read_then_write(fn): with open(fn) as read_file: data = read_file.read() print(read_file) # ... transform the data as required ... with open(fn, "w") as write_file: write_file.write(data) print(write_file) After each 'with' block, the file object is still there. You can refer to it. Nothing has destroyed the object. But the file has been closed, guaranteeing that you can safely reopen it in a different mode (regardless of your OS). The same could be done with this timer; an __exit__ method would make a lot of sense here, and would allow the timer to be used in a with block to govern its execution. (It also isn't really necessary, but if you want a good Pythonic way to show the beginning and end of its use area, a 'with' block is the way to go.) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
Chris Angelico writes: > On Thu, 3 Feb 2022 at 09:33, Barry wrote: > (Side point: The OP's code is quite inefficient, as it creates a new > thread for each reiteration, but there's nothing wrong with that if > you're looking for something simple.) It is just something I wrote fast. How could I do this in a better way? > (regardless of your OS). The same could be done with this timer; an > __exit__ method would make a lot of sense here, and would allow the > timer to be used in a with block to govern its execution. (It also > isn't really necessary, but if you want a good Pythonic way to show > the beginning and end of its use area, a 'with' block is the way to > go.) I will look into that. -- Cecil Westerhof Senior Software Engineer LinkedIn: http://www.linkedin.com/in/cecilwesterhof -- https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
Cecil Westerhof writes:
>> (regardless of your OS). The same could be done with this timer; an
>> __exit__ method would make a lot of sense here, and would allow the
>> timer to be used in a with block to govern its execution. (It also
>> isn't really necessary, but if you want a good Pythonic way to show
>> the beginning and end of its use area, a 'with' block is the way to
>> go.)
>
> I will look into that.
Implemented:
from threading import Timer
class repeated_timer(object):
def __init__(self, fn, interval, start = False):
if not callable(fn):
raise TypeError('{} is not a function'.format(fn))
self._fn = fn
self._check_interval(interval)
self._interval = interval
self._timer = None
self._is_running = False
if start:
self.start()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.stop()
def _check_interval(self, interval):
if not type(interval) in [int, float]:
raise TypeError('{} is not numeric'.format(interval))
if interval <= 0:
raise ValueError('{} is not greater as 0'.format(interval))
def _next(self):
self._timer = Timer(self._interval, self._run)
self._timer.start()
def _run(self):
self._next()
self._fn()
def set_interval(self, interval):
self._check_interval(interval)
self._interval = interval
def start(self):
if not self._is_running:
self._is_running = True
self._next()
def stop(self):
if self._is_running:
self._timer.cancel()
self._timer = None
self._is_running = False
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
--
https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
You have:
def _check_interval(self, interval):
if not type(interval) in [int, float]:
raise TypeError('{} is not numeric'.format(interval))
This check is better written:
if not isinstance(interval, (int,float)):
which handles subclasses of these types (but note that bool subclasses
int :-) normally we don't care), or behaviourally:
try:
interval = float(interval)
except ValueError as e:
raise TypeError(
"cannot convert %s:%r to float: %s"
% (type(interval).__name__, interval, e)) from e
which tries to convert to float and fails if that does not work, which
supports classes with a __float__ method (these classes are rare, but
decimal.Decimal is one example).
I'd probably use the isinstance() form myself.
Cheers,
Cameron Simpson
--
https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
On Thu, 3 Feb 2022 at 12:24, Cecil Westerhof via Python-list wrote: > > Chris Angelico writes: > > > On Thu, 3 Feb 2022 at 09:33, Barry wrote: > > (Side point: The OP's code is quite inefficient, as it creates a new > > thread for each reiteration, but there's nothing wrong with that if > > you're looking for something simple.) > > It is just something I wrote fast. How could I do this in a better way? I'll answer your question, but first and foremost: Your code was fine, and if something does what it's supposed to, that is the most important. Everything else is minor. But for other ways to do things, I would recommend creating a single thread function and spawning a single thread to run it, and then having that function call the target every N seconds. Also, consider subclassing Thread rather than subclassing object (which, btw, is the default; you don't need to say "class X(object)"), which will automatically give your object all the methods of a timer. If you feel like it, you could even look into ways to do things without threads, but that would be a much bigger change :) But remember: when your code does what it's supposed to, it is *fine*, and doesn't need changing. I'm not saying that your code is bad :) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Data unchanged when passing data to Python in multiprocessing shared memory
Jen, I would not be shocked at incompatibilities in the system described making it hard to exchange anything, including text, but am not clear if there is a limitation of four bytes in what can be shared. For me, a character string can use any number of contiguous bytes in memory that some kind of pointer or table lookup provides access to. Clearly you could squeeze larger number in by not writing decimals but using hexadecimal notation that adds a to f as valid entries, and of course you can make your own customized base 32 or if you use more symbols (such as upper and lower case as different) you could add a few symbols and stretch it out to base 60 or 64. Like I said, I may have missed something. If you KNOW that system A will interact with systems B and C and so on, and each machine knows what kind it is, and especially if it knows which kind of machine left it something in shared memory, there has to be a way to coordinate between them. If character strings in ASCII or UTF8 or EBCDIC or some kind of raw are allowed, and used with just a few characters that can spell out numbers, I would think much is possible. If needed, perhaps a fixed size could be set aside and the string use a null terminator if shorter. Of course if this big-endian issue also scrambles bytes used in strings, forget it. Or, maybe shared memory is not the easy way to go, even it it might be faster. -Original Message- From: Jen Kris To: Avi Gross Cc: [email protected] Sent: Wed, Feb 2, 2022 1:27 pm Subject: Re: Data unchanged when passing data to Python in multiprocessing shared memory An ASCII string will not work. If you convert 32894 to an ascii string you will have five bytes, but you need four. In my original post I showed the C program I used to convert any 32-bit number to 4 bytes. Feb 2, 2022, 10:16 by [email protected]: I applaud trying to find the right solution but wonder if a more trivial solution is even being considered. It ignores big and little endians and just converts your data into another form and back. If all you want to do is send an integer that fit in 32 bits or 64 bits, why not convert it to a character string in a form that both machines will see the same way and when read back, convert it back to an integer? As long as both side see the same string, this can be done in reasonable time and portably. Or am I missing something? Is "1234" not necessarily seen in the same order, or "1.234e3" or whatever? Obviously, if the mechanism is heavily used and multiple sides keep reading and even writing the same memory location, this is not ideal. But having different incompatible processors looking at the same memory is also not. -Original Message- From: Dennis Lee Bieber To: [email protected] Sent: Wed, Feb 2, 2022 12:30 am Subject: Re: Data unchanged when passing data to Python in multiprocessing shared memory On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris declaimed the following: breakup = int.from_bytes(byte_val, "big") >print("this is breakup " + str(breakup)) >Python prints: this is breakup 32894 >Note that I had to switch from little endian to big endian. Python is little >endian by default, but in this case it's big endian. Look at the struct module. I'm pretty certain it has flags for big or little end, or system native (that, or run your integers through the various "network byte order" functions that I think C and Python both support. https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html >However, if anyone on this list knows how to pass data from a non-Python >language to Python in multiprocessing.shared_memory please let me (and the >list) know. MMU cache lines not writing through to RAM? Can't find anything on Google to force a cache flush Can you test on a different OS? (Windows vs Linux) -- Wulfraed Dennis Lee Bieber AF6VN [email protected] http://wlfraed.microdiversity.freeddns.org/ -- https://mail.python.org/mailman/listinfo/python-list -- https://mail.python.org/mailman/listinfo/python-list -- https://mail.python.org/mailman/listinfo/python-list
Re: Data unchanged when passing data to Python in multiprocessing shared memory
On Thu, 3 Feb 2022 at 13:32, Avi Gross via Python-list wrote: > > Jen, > > I would not be shocked at incompatibilities in the system described making it > hard to exchange anything, including text, but am not clear if there is a > limitation of four bytes in what can be shared. For me, a character string > can use any number of contiguous bytes in memory that some kind of pointer or > table lookup provides access to. > > Clearly you could squeeze larger number in by not writing decimals but using > hexadecimal notation that adds a to f as valid entries, and of course you can > make your own customized base 32 or if you use more symbols (such as upper > and lower case as different) you could add a few symbols and stretch it out > to base 60 or 64. > > Like I said, I may have missed something. If you KNOW that system A will > interact with systems B and C and so on, and each machine knows what kind it > is, and especially if it knows which kind of machine left it something in > shared memory, there has to be a way to coordinate between them. If character > strings in ASCII or UTF8 or EBCDIC or some kind of raw are allowed, and used > with just a few characters that can spell out numbers, I would think much is > possible. If needed, perhaps a fixed size could be set aside and the string > use a null terminator if shorter. > > Of course if this big-endian issue also scrambles bytes used in strings, > forget it. > > Or, maybe shared memory is not the easy way to go, even it it might be faster. > Structs are fine, and are highly unlikely to be the OP's problem. Switching to a different system won't help. Unfortunately I can't offer any serious help about the actual problem, as I don't know what's going on with the shared memory issue. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
Cameron Simpson writes:
> You have:
>
> def _check_interval(self, interval):
> if not type(interval) in [int, float]:
> raise TypeError('{} is not numeric'.format(interval))
>
> This check is better written:
>
> if not isinstance(interval, (int,float)):
>
> which handles subclasses of these types (but note that bool subclasses
> int :-)
Done, thanks.
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
--
https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
On 2022-02-03 at 12:39:43 +1100,
Cameron Simpson wrote:
> You have:
>
> def _check_interval(self, interval):
> if not type(interval) in [int, float]:
> raise TypeError('{} is not numeric'.format(interval))
>
> This check is better written:
>
> if not isinstance(interval, (int,float)):
>
> which handles subclasses of these types (but note that bool subclasses
> int :-) normally we don't care), or behaviourally:
>
> try:
> interval = float(interval)
> except ValueError as e:
> raise TypeError(
> "cannot convert %s:%r to float: %s"
> % (type(interval).__name__, interval, e)) from e
>
> which tries to convert to float and fails if that does not work, which
> supports classes with a __float__ method (these classes are rare, but
> decimal.Decimal is one example).
I think this can be simplified for time intervals to the following:
if interval <= 0:
raise ValueError(...)
which accepts non-negative real values; throws ValueError for negative
real values; and TypeError for other stuff, including complex numbers
(pathological types notwithstanding). One thing that doesn't work right
is NaNs, but I'm sure it's not the only code that acts weirdly when
faced with a NaM (curiously, Timer accepts a NaN, but the text I get
from help(Timer) in Python 3.10.2 is, well, broken).
FWIW, I'd find some way to tell users the units (seconds, milliseconds,
fortnights, etc.) instead of making them wade through your code to find
the call to (and possibly the [broken] help text of) Timer.
--
https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
On Thu, 3 Feb 2022 at 14:52, <[email protected]> wrote: > > On 2022-02-03 at 12:39:43 +1100, > Cameron Simpson wrote: > > > You have: > > > > def _check_interval(self, interval): > > if not type(interval) in [int, float]: > > raise TypeError('{} is not numeric'.format(interval)) > > > > This check is better written: > > > > if not isinstance(interval, (int,float)): > > > > which handles subclasses of these types (but note that bool subclasses > > int :-) normally we don't care), or behaviourally: > > > > try: > > interval = float(interval) > > except ValueError as e: > > raise TypeError( > > "cannot convert %s:%r to float: %s" > > % (type(interval).__name__, interval, e)) from e > > > > which tries to convert to float and fails if that does not work, which > > supports classes with a __float__ method (these classes are rare, but > > decimal.Decimal is one example). > > I think this can be simplified for time intervals to the following: > > if interval <= 0: > raise ValueError(...) That's checking something quite different, though. Casting to float will accept anything that can be, well, cast to float, but checking for less than or equal to zero demands that it already be some sort of number. It's debatable which check is more correct, but certainly this is not a simplification of the other code, it's a distinctly different validation. > which accepts non-negative real values; throws ValueError for negative > real values; and TypeError for other stuff, including complex numbers > (pathological types notwithstanding). One thing that doesn't work right > is NaNs, but I'm sure it's not the only code that acts weirdly when > faced with a NaM (curiously, Timer accepts a NaN, but the text I get > from help(Timer) in Python 3.10.2 is, well, broken). Strange. The text I get in 3.11.0a1 is fine. But in any case, there's always the docs on the web. https://docs.python.org/3/library/threading.html#timer-objects > FWIW, I'd find some way to tell users the units (seconds, milliseconds, > fortnights, etc.) instead of making them wade through your code to find > the call to (and possibly the [broken] help text of) Timer. In anything in Python, assume that the unit is seconds. With anything that accepts floats (where these can be distinguished from integers), assume the unit is seconds. If it accepts micro or nanoseconds, it'll almost certainly be called "high resolution timer" (unless it accepts two args, sec and us/ns, but that's pretty obvious), so you can generally exclude those too. The only real question is whether sleep(int) takes seconds or milliseconds, which isn't a problem here. Citation: I've slept in many many programming languages and frameworks. Which sounds seriously weird, but you're all programmers, you know what I mean :) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
On 2022-02-03 at 15:07:22 +1100, Chris Angelico wrote: > On Thu, 3 Feb 2022 at 14:52, <[email protected]> wrote: > > > > On 2022-02-03 at 12:39:43 +1100, > > Cameron Simpson wrote: > > > > > You have: > > > > > > def _check_interval(self, interval): > > > if not type(interval) in [int, float]: > > > raise TypeError('{} is not numeric'.format(interval)) > > > > > > This check is better written: > > > > > > if not isinstance(interval, (int,float)): > > > > > > which handles subclasses of these types (but note that bool subclasses > > > int :-) normally we don't care), or behaviourally: > > > > > > try: > > > interval = float(interval) > > > except ValueError as e: > > > raise TypeError( > > > "cannot convert %s:%r to float: %s" > > > % (type(interval).__name__, interval, e)) from e > > > > > > which tries to convert to float and fails if that does not work, which > > > supports classes with a __float__ method (these classes are rare, but > > > decimal.Decimal is one example). > > > > I think this can be simplified for time intervals to the following: > > > > if interval <= 0: > > raise ValueError(...) > > That's checking something quite different, though. Casting to float > will accept anything that can be, well, cast to float, but checking > for less than or equal to zero demands that it already be some sort of > number. It's debatable which check is more correct, but certainly this > is not a simplification of the other code, it's a distinctly different > validation. Okay, "simplified" isn't quite the right word. Given two examples (with known deficiencies) and no actual use cases or specifications, I added a third example, which I believed was simpler (and arguably better in one or more ways, which I explained), than the others. > > which accepts non-negative real values; throws ValueError for negative > > real values; and TypeError for other stuff, including complex numbers > > (pathological types notwithstanding). One thing that doesn't work right > > is NaNs, but I'm sure it's not the only code that acts weirdly when > > faced with a NaM (curiously, Timer accepts a NaN, but the text I get > > from help(Timer) in Python 3.10.2 is, well, broken). > > Strange. The text I get in 3.11.0a1 is fine. But in any case, there's > always the docs on the web. > > https://docs.python.org/3/library/threading.html#timer-objects help(Timer) is built into my REPL (and likely consumed by development systems and IDEs everywhere). No web necessary. > > FWIW, I'd find some way to tell users the units (seconds, milliseconds, > > fortnights, etc.) instead of making them wade through your code to find > > the call to (and possibly the [broken] help text of) Timer. > > In anything in Python, assume that the unit is seconds. With anything > that accepts floats (where these can be distinguished from integers), > assume the unit is seconds. If it accepts micro or nanoseconds, it'll > almost certainly be called "high resolution timer" (unless it accepts > two args, sec and us/ns, but that's pretty obvious), so you can > generally exclude those too. The only real question is whether > sleep(int) takes seconds or milliseconds, which isn't a problem here. > > Citation: I've slept in many many programming languages and > frameworks. Which sounds seriously weird, but you're all programmers, > you know what I mean :) I've slept in enough programming environments to know better than to assume anything. ;-) -- https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
On Thu, 3 Feb 2022 at 15:28, <[email protected]> wrote: > > On 2022-02-03 at 15:07:22 +1100, > Chris Angelico wrote: > > > On Thu, 3 Feb 2022 at 14:52, <[email protected]> wrote: > > > > > > On 2022-02-03 at 12:39:43 +1100, > > > Cameron Simpson wrote: > > > > > > > You have: > > > > > > > > def _check_interval(self, interval): > > > > if not type(interval) in [int, float]: > > > > raise TypeError('{} is not numeric'.format(interval)) > > > > > > > > This check is better written: > > > > > > > > if not isinstance(interval, (int,float)): > > > > > > > > which handles subclasses of these types (but note that bool subclasses > > > > int :-) normally we don't care), or behaviourally: > > > > > > > > try: > > > > interval = float(interval) > > > > except ValueError as e: > > > > raise TypeError( > > > > "cannot convert %s:%r to float: %s" > > > > % (type(interval).__name__, interval, e)) from e > > > > > > > > which tries to convert to float and fails if that does not work, which > > > > supports classes with a __float__ method (these classes are rare, but > > > > decimal.Decimal is one example). > > > > > > I think this can be simplified for time intervals to the following: > > > > > > if interval <= 0: > > > raise ValueError(...) > > > > That's checking something quite different, though. Casting to float > > will accept anything that can be, well, cast to float, but checking > > for less than or equal to zero demands that it already be some sort of > > number. It's debatable which check is more correct, but certainly this > > is not a simplification of the other code, it's a distinctly different > > validation. > > Okay, "simplified" isn't quite the right word. Given two examples (with > known deficiencies) and no actual use cases or specifications, I added a > third example, which I believed was simpler (and arguably better in one > or more ways, which I explained), than the others. Fair :) I'm unsure which is the best check here, or whether it's worth having any check at all (you could just let the Timer - or time.sleep() - do the checks). > > Strange. The text I get in 3.11.0a1 is fine. But in any case, there's > > always the docs on the web. > > > > https://docs.python.org/3/library/threading.html#timer-objects > > help(Timer) is built into my REPL (and likely consumed by development > systems and IDEs everywhere). No web necessary. Agreed, and my primary response is that it's fine in my 3.11, so it's probably something fixable. The web docs are a good fallback though. > I've slept in enough programming environments to know better than to > assume anything. ;-) Excellent :) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
Chris Angelico writes: >> > (Side point: The OP's code is quite inefficient, as it creates a new >> > thread for each reiteration, but there's nothing wrong with that if >> > you're looking for something simple.) >> >> It is just something I wrote fast. How could I do this in a better way? > > I'll answer your question, but first and foremost: Your code was fine, > and if something does what it's supposed to, that is the most > important. Everything else is minor. I like to write efficient code and it never hurts to write better code as just doing what it is supposed to do. ;-) And in my case interval is .5 seconds and when someone is going to use it with an even smaller interval … > But for other ways to do things, I would recommend creating a single > thread function and spawning a single thread to run it, and then > having that function call the target every N seconds. Also, consider Have to be careful that timing keeps correct when target takes a 'lot' of time. Something to ponder about, but can wait. > subclassing Thread rather than subclassing object (which, btw, is the > default; you don't need to say "class X(object)"), which will > automatically give your object all the methods of a timer. Of-course. I should have thought about that. :'-( -- Cecil Westerhof Senior Software Engineer LinkedIn: http://www.linkedin.com/in/cecilwesterhof -- https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
On Thu, 3 Feb 2022 at 15:43, Cecil Westerhof via Python-list wrote: > > Chris Angelico writes: > > >> > (Side point: The OP's code is quite inefficient, as it creates a new > >> > thread for each reiteration, but there's nothing wrong with that if > >> > you're looking for something simple.) > >> > >> It is just something I wrote fast. How could I do this in a better way? > > > > I'll answer your question, but first and foremost: Your code was fine, > > and if something does what it's supposed to, that is the most > > important. Everything else is minor. > > I like to write efficient code and it never hurts to write better code > as just doing what it is supposed to do. ;-) > > And in my case interval is .5 seconds and when someone is going to use > it with an even smaller interval … > > > > But for other ways to do things, I would recommend creating a single > > thread function and spawning a single thread to run it, and then > > having that function call the target every N seconds. Also, consider > > Have to be careful that timing keeps correct when target takes a 'lot' > of time. > Something to ponder about, but can wait. Ah. In that case, I would recommend a different look at things. Instead of waiting X time, then firing the event, then waiting X time, consider instead an interval timer based on monotonic time: https://docs.python.org/3/library/time.html#time.monotonic When the timer starts, record the current monotonic time, and sleep one interval. After the function returns, sleep the remainder of one interval. It's up to you what happens if you ever find that the next time point has already passed - do you call the function immediately, or skip and wait for the next moment? Interval timers have some complexity to them, but it's worth putting in the time (pun intended) to figure out how these things work :) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
[email protected] writes: > FWIW, I'd find some way to tell users the units (seconds, milliseconds, > fortnights, etc.) instead of making them wade through your code to find > the call to (and possibly the [broken] help text of) Timer. You mean with docstring? -- Cecil Westerhof Senior Software Engineer LinkedIn: http://www.linkedin.com/in/cecilwesterhof -- https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
Cecil Westerhof writes:
> I need (sometimes) to repeatedly execute a function. For this I wrote
> the below class. What do you think about it?
I wrote some unit test for the class. Is this the correct way to do
this?
For example in test_correct_params_no_start I check four things. Some
people say you should not check more as one.
By the way it was good that I defined __enter__ and __exit__. :-D
#!/usr/bin/env python3
import unittest
from threading import Timer
from repeated_timer import repeated_timer
class test_repeated_timer(unittest.TestCase):
def test_interval_zero(self):
with self.assertRaises(ValueError):
rt = repeated_timer(dummy_fn, 0)
def test_interval_negative(self):
with self.assertRaises(ValueError):
rt = repeated_timer(dummy_fn, -1)
def test_interval_string(self):
with self.assertRaises(TypeError):
rt = repeated_timer(dummy_fn, '.4')
def test_non_function(self):
with self.assertRaises(TypeError):
rt = repeated_timer('dummy_fn', .5)
def test_correct_params_no_start(self):
rt = repeated_timer(dummy_fn, .5)
self.assertEqual(rt._fn, dummy_fn)
self.assertEqual(rt._interval, .5)
self.assertEqual(rt._timer,None)
self.assertFalse(rt._is_running)
def test_correct_params_do_start(self):
with repeated_timer(dummy_fn, .375, True) as rt:
self.assertEqual(rt._fn, dummy_fn)
self.assertEqual(rt._interval, .375)
self.assertTrue (isinstance(rt._timer, Timer), 'There should be
a timer')
self.assertTrue (rt._is_running, 'Should be
running')
def test__start_later(self):
with repeated_timer(dummy_fn, .5) as rt:
self.assertEqual(rt._fn, dummy_fn)
self.assertEqual(rt._interval, .5)
self.assertEqual(rt._timer,None)
self.assertFalse(rt._is_running)
rt.start()
self.assertEqual(rt._fn, dummy_fn)
self.assertEqual(rt._interval, .5)
self.assertTrue (isinstance(rt._timer, Timer), 'There should be
a timer')
self.assertTrue (rt._is_running, 'Should be
running')
def dummy_fn():
pass
if __name__ == '__main__':
unittest.main()
> from threading import Timer
>
>
>
> class repeated_timer(object):
> def __init__(self, fn, interval, start = False):
> if not callable(fn):
> raise TypeError('{} is not a function'.format(fn))
> self._fn = fn
> self._check_interval(interval)
> self._interval = interval
> self._timer = None
> self._is_running = False
> if start:
> self.start()
>
> def _check_interval(self, interval):
> if not type(interval) in [int, float]:
> raise TypeError('{} is not numeric'.format(interval))
> if interval <= 0:
> raise ValueError('{} is not greater as 0'.format(interval))
>
> def _next(self):
> self._timer = Timer(self._interval, self._run)
> self._timer.start()
>
> def _run(self):
> self._next()
> self._fn()
>
> def set_interval(self, interval):
> self._check_interval(interval)
> self._interval = interval
>
> def start(self):
> if not self._is_running:
> self._next()
> self._is_running = True
>
> def stop(self):
> if self._is_running:
> self._timer.cancel()
> self._timer = None
> self._is_running = False
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
--
https://mail.python.org/mailman/listinfo/python-list
Re: Waht do you think about my repeated_timer class
Chris Angelico writes: > On Thu, 3 Feb 2022 at 15:43, Cecil Westerhof via Python-list > wrote: >> >> Chris Angelico writes: >> >> >> > (Side point: The OP's code is quite inefficient, as it creates a new >> >> > thread for each reiteration, but there's nothing wrong with that if >> >> > you're looking for something simple.) >> >> >> >> It is just something I wrote fast. How could I do this in a better way? >> > >> > I'll answer your question, but first and foremost: Your code was fine, >> > and if something does what it's supposed to, that is the most >> > important. Everything else is minor. >> >> I like to write efficient code and it never hurts to write better code >> as just doing what it is supposed to do. ;-) >> >> And in my case interval is .5 seconds and when someone is going to use >> it with an even smaller interval … >> >> >> > But for other ways to do things, I would recommend creating a single >> > thread function and spawning a single thread to run it, and then >> > having that function call the target every N seconds. Also, consider >> >> Have to be careful that timing keeps correct when target takes a 'lot' >> of time. >> Something to ponder about, but can wait. > > Ah. In that case, I would recommend a different look at things. > Instead of waiting X time, then firing the event, then waiting X time, > consider instead an interval timer based on monotonic time: > > https://docs.python.org/3/library/time.html#time.monotonic > > When the timer starts, record the current monotonic time, and sleep > one interval. After the function returns, sleep the remainder of one > interval. It's up to you what happens if you ever find that the next > time point has already passed - do you call the function immediately, > or skip and wait for the next moment? > > Interval timers have some complexity to them, but it's worth putting > in the time (pun intended) to figure out how these things work :) I will look into it. -- Cecil Westerhof Senior Software Engineer LinkedIn: http://www.linkedin.com/in/cecilwesterhof -- https://mail.python.org/mailman/listinfo/python-list
