Как правильно спать бесконечно? - PullRequest
0 голосов
/ 07 мая 2018

В моем коде запущено несколько потоков, и мне нужно, чтобы в конце скрипта он спал бесконечно, без того, чтобы этот сон был основным ударом по производительности 1 .

Одной возможностью может быть бесконечный цикл с коротким сном:

while True:
    time.sleep(1)

или долго спать

time.sleep(4000000)

или

import signal
signal.pause()

Но:

  • Мне не удалось найти самое большое время, которое может принять сон (sys.maxint слишком велико)

  • signal.pause() реализовано только в Unix

  • и первый "цикл сна" не выглядит мне чистым (почему 1 секунда, а не 10 или 0,1?)

Есть ли чистый, питонный способ спать бесконечно?


1 Я не управляю потоками напрямую, иначе я бы пошел на threading.Thread.join(), так как сами потоки не заканчиваются.

1 Ответ

0 голосов
/ 07 мая 2018

threading.enumerate дает вам список всех запущенных потоков, включая основной, так что вы можете сделать это:

main_thread = threading.main_thread()
while True:
    L = threading.enumerate()
    L.remove(main_thread)  # or avoid it in the for loop
    for t in L:
        t.join()

while True необходим в том случае, если ваша библиотека создает новые потоки, пока вы ожидаете завершения текущих.

Предполагая, что никакие потоки не создаются во время работы enumerate, вы можете проверить, имеет ли L только один элемент (основной поток), и если это так, разорвать цикл. В сочетании с предложением Тадхга Макдональда-Дженсена об использовании iter со стражем, получаем:

main_thread = threading.main_thread()
main_threads = [main_thread, ]  # WARN: can't have more than one thread here
for threads in iter(threading.enumerate, main_threads):
    for t in threads:
        if t == main_thread:
            continue
        t.join()

enumerate возвращает список в неопределенном порядке, поэтому, если у вас более одного «основного» потока, порядок начинает иметь значение. Решением будет использование наборов , то есть main_threads = {main_thread, } и iter(lambda : set(threading.enumerate()), main_threads).

Если вы предпочитаете EAFP подход просить прощения вместо разрешения, и все ваши потоки запускаются, когда вы достигаете конца вашего сценария, вы также можете сделать это:

for thread in threading.enumerate():
    try:
        thread.join()
    except RuntimeError:
        # trying to join the main thread, which would create a deadlock (see https://docs.python.org/3/library/threading.html#threading.Thread.join for details)
        pass
...