Pitfalls ======== This page documents some common pitfalls when using Live Cells. Please go through this page carefully before using this library. ========= Threading ========= Cells are not thread safe and their values should only be read, changed from a single thread. All interactions with cells should be designated to a single thread, which serves as the "main" thread. Care needs to be taken when using Live Cells with *green threading* libraries such as `gevent `_ and `eventlet `_. *Green threads* are lightweight threads, with multiple green threads running on a single OS thread. In general green threading libraries work by *monkey-patching* functions which perform blocking IO and replacing them with asynchronous variants. When a "blocking" function is called in a green thread, the thread yields execution to another green thread until the blocking operation completes. It is safe to read and even change the values of cells from multiple green threads, provided the green threads run on a single OS thread. However, the process of updating the values of cells should not be interrupted. To avoid this you should adhere to the following rules: * **Do not** call blocking IO functions within computed cells. * **Do not** call blocking IO functions in a context managed by :any:`live_cells.batch`. * Blocking IO functions may only be called within a watch functions which are scheduled to run on a new green thread. Regarding the last point, if you must call a blocking IO function inside a watch function, you should provide a ``schedule`` function that creates a new green thread on which the watch function is run. For example, if you're using *gevent* provide ``gevent.spawn`` as the ``schedule`` function. Here's an example: .. code-block:: python import gevent import live_cells as lc a = lc.mutable(0) @lc.watch(schedule=gevent.spawn) def watch_a(): print(f'A = {a()}') log_to_file(a()) a.value = 2 a.value = 10 There is no danger of missed updates because the watch function sees the values of the referenced cells, ``a`` in this case, as they are at the time the watch function is scheduled and not at the time the watch function is run. In this example, the following is printed to standard output: .. code-block:: text A = 0 A = 2 A = 10 Even though the value of ``a`` is changed to ``10`` immediately after it is set to ``2`` before the watch function has been run.