It looks like you're new here. If you want to get involved, click one of these buttons!
Hi Matthias,
I know you are probably going to hate me for this ![]()
But do you have a somewhat comprehensive list of what is thread-safe in KLayout?
Out of interest (and because in some cases it would be somewhat useful) I made a kfactory version which in the new python 3.14 works with the freethreading (i.e. no GIL). I know that you mentioned before that KLayout should be reasonably thread-safe if you are not modifying a cell or any of it's children while working on it.
But to me it even fails on c.each_inst() when another cell is currently being built. each_inst() even fails for an empty cell. This fails with a topological sort error.
Do you have any advice how I could fix this or what might cause this?
If you would like to test it, the branch is here https://github.com/gdsfactory/kfactory/tree/add-3.14-threading
Test case is the following:
import time
from concurrent.futures import ThreadPoolExecutor
from threading import get_ident
import kfactory as kf
kf.config.logfilter.level = "DEBUG"
def busy_wait(duration: float) -> None:
"""Actively burn CPU time for `duration` seconds."""
start = time.perf_counter()
while (time.perf_counter() - start) < duration:
pass # no sleep, no yield — pure busy loop
@kf.cell
def straight(length: int) -> kf.KCell:
c = kf.KCell()
layer = c.kcl.layer(1, 0)
# c.shapes(layer).insert(kf.kdb.Box(length, 500))
# busy_wait(1)
# print(f"{length=}")
return c
def test() -> kf.kdb.Cell:
c = ly.create_cell(name=f"{get_ident()}")
c.name = str(c.cell_index())
return c
def main() -> None:
with ThreadPoolExecutor(max_workers=32) as executor:
start = time.perf_counter()
futures = [executor.submit(straight, i * 1000 + 100) for i in range(2000)]
for i, f in enumerate(futures):
try:
f.result()
except Exception as e:
raise RuntimeError(f"Failed to build for {i=!r}") from e
end = time.perf_counter()
print(f"Took {end - start:.2f} seconds")
if __name__ == "__main__":
main()
Comments
Hi @sebastian,
Well, I ran out of hate - there are a few people out there currently, who really deserve it, and I used up all of it, just for them.
KLayout is partially thread safe. Here are some rules:
In C++, as a rule of thumb, "const" methods are thread safe, "non-const" ones are not. As constness is documented in the API, this should give you some guideline. Note that when using "non-const" methods, other threads should not access the object, not even from "const" methods.
That architecture is governed by the requirement of having multiple drawing or analysis threads, like in the tiling processor. But a "divide and conquer" approach is possible.
KLayout does not call Python code from multiple threads in parallel as that was not possible before FT Python. I still can't imagine that Python itself is fully free threaded. Maybe they just replaced the GIL by more detailed locks, for example on the reference counters. A similar thing needs to happen in the C extensions and I don't think many of them are prepared already.
Matthias
Hi Matthias,
Thanks for the clarification.
I also assume that it's not easy to make other (non-destructive) things threadsafe? In particular I am thinking of
Cell.insert(const CellInstArray cell_inst_array)If that was threadsafe I could lock the other things behind locks and semaphores, but this one would probably take most of the times where it would stall other threads too much.
If it's not easily possible, I'll just put this adventure on ice for now
Thanks for the info anyways!
Sebastian