Подтвердить что ты не робот

Что такое поток python

У меня есть несколько вопросов, касающихся потоков Python.

  • Является ли поток Python реализацией Python или ОС?
  • Когда я использую htop, многопоточный script имеет несколько записей - такое же потребление памяти, та же команда, но другой PID. Означает ли это, что поток [Python] на самом деле является особым видом процесса? (Я знаю, что в htop есть параметр, чтобы показать эти потоки как один процесс - Hide userland threads)
  • Документация говорит:

Поток может быть помечен как "поток демона". Значение этого flag заключается в том, что вся программа Python завершается, когда только потоки демона остаются.

Моя интерпретация/понимание: основной поток завершается, когда все не-демонные потоки завершаются.

Итак, потоки демона python не являются частью программы Python, если "вся программа Python завершается, когда остаются только потоки демона"?

4b9b3361

Ответ 1

  • Нить Python реализована с использованием потоков ОС во всей реализации, которую я знаю (C Python, PyPy и Jython). Для каждого потока Python существует основной поток ОС.

  • Некоторые операционные системы (одна из которых Linux) предоставляют все разные потоки, запущенные одним и тем же исполняемым файлом в списке всех запущенных процессов. Это деталь реализации ОС, а не Python. В некоторых других операционных системах вы можете не видеть эту нить при перечислении всех процессов.

  • Процесс завершится, когда закончится последний не-демона. В этот момент все потоки демона будут прекращены. Таким образом, эти потоки являются частью вашего процесса, но не препятствуют его прекращению (в то время как регулярный поток предотвратит его). Это реализовано в чистом Python. Процесс завершается, когда вызывается функция _exit (она будет убивать все потоки), и когда основной поток завершается (или sys.exit), интерпретатор Python проверяет, существует ли другой поток не-демона. Если нет, то он вызывает _exit, в противном случае он ожидает завершения потоков, отличных от daemon.


Флаг потока демона реализован в чистом Python модулем threading. Когда модуль загружен, создается объект Thread для представления основного потока, а метод _exitfunc зарегистрирован как atexit.

Код этой функции:

class _MainThread(Thread):

    def _exitfunc(self):
        self._Thread__stop()
        t = _pickSomeNonDaemonThread()
        if t:
            if __debug__:
                self._note("%s: waiting for other threads", self)
        while t:
            t.join()
            t = _pickSomeNonDaemonThread()
        if __debug__:
            self._note("%s: exiting", self)
        self._Thread__delete()

Эта функция будет вызываться интерпретатором Python при вызове sys.exit или при завершении основного потока. Когда функция возвращается, интерпретатор вызовет функцию _exit системы. И функция прекратится, когда будут выполняться только потоки демона (если есть).

Когда вызывается функция _exit, ОС завершает все потоки процесса, а затем завершает процесс. Время выполнения Python не будет вызывать функцию _exit до тех пор, пока не будет выполнен весь поток без демона.

Весь поток является частью процесса.


Моя интерпретация/понимание: основной поток завершается, когда все не-daemon-потоки завершаются.

Итак, потоки демона python не являются частью программы python, если "весь Программа Python выйдет, когда оставлены только потоки демона??

Ваше понимание неверно. Для ОС процесс состоит из множества потоков, каждый из которых равен (нет ничего особенного в основном потоке для ОС, за исключением того, что среда выполнения C добавляет вызов к _exit в конце функции main). И ОС не знает о потоке демона. Это чисто концепция Python.

интерпретатор Python использует собственный поток для реализации потока Python, но должен помнить список созданных потоков. И используя его atexit hook, он гарантирует, что функция _exit вернется в ОС только при завершении последнего не-демона. При использовании "всей программы Python" документация относится ко всему процессу.


Следующая программа может помочь понять разницу между потоком демона и регулярным потоком:

import sys
import time
import threading

class WorkerThread(threading.Thread):

    def run(self):
        while True:
            print 'Working hard'
            time.sleep(0.5)

def main(args):
    use_daemon = False
    for arg in args:
        if arg == '--use_daemon':
            use_daemon = True
    worker = WorkerThread()
    worker.setDaemon(use_daemon)
    worker.start()
    time.sleep(1)
    sys.exit(0)

if __name__ == '__main__':
    main(sys.argv[1:])

Если вы выполните эту программу с помощью "-use_daemon", вы увидите, что программа будет печатать только небольшое количество строк Working hard. Без этого флага программа не будет завершена даже при завершении основного потока, и программа будет печатать строки Working hard до тех пор, пока не будет убита.

Ответ 2

Я не знаком с реализацией, поэтому дайте эксперимент:

import threading
import time

def target():
    while True:
        print 'Thread working...'
        time.sleep(5)

NUM_THREADS = 5

for i in range(NUM_THREADS):
    thread = threading.Thread(target=target)
    thread.start()
  • Число потоков, о которых было написано с помощью ps -o cmd,nlwp <pid>, составляет NUM_THREADS+1 (еще один для основного потока), поэтому, если инструменты ОС обнаруживают количество потоков, они должны быть потоками ОС. Я попробовал оба с cpython и jython, и, несмотря на то, что в jython есть некоторые другие потоки, для каждого добавочного потока, который я добавляю, ps увеличивает количество потоков на единицу.

  • Я не уверен в поведении htop, но ps кажется последовательным.

  • Я добавил следующую строку перед началом потоков:

    thread.daemon = True
    

    Когда я выполнил использование cpython, программа завершилась почти сразу, и процесс не был найден с использованием ps, поэтому я предполагаю, что программа завершена вместе с потоками. В jython программа работала одинаково (она не завершалась), поэтому, возможно, есть некоторые другие потоки из jvm, которые не позволяют потокам программы завершить работу или потоки демона.

Примечание. Я использовал Ubuntu 11.10 с python 2.7.2+ и jython 2.2.1 на java1.6.0_23

Ответ 3

  • Потоки Python - это практически реализация интерпретатора, потому что так называемый глобальный интерпретатор (GIL), даже если он технически использует механизмы потоковой передачи уровня. На * nix он использует pthreads, но GIL effectivly делает его гибридом, застрявшим на парадигме потоков на уровне приложений. Таким образом, вы увидите его в системах * nix несколько раз в выводе ps/top, но он по-прежнему ведет себя (по производительности), как реализованный программным потоком.

  • Нет, вы просто видите вид базовой реализации ваших os. Этот тип поведения обнаруживается с помощью nix pthread-like threading или им сказано, что даже окна реализуют потоки таким образом.

  • Когда ваша программа закрывается, она ждет завершения всех потоков. Если у вас есть потоки, которые могут отложить выход неопределенно, может быть разумным отметить эти потоки как "демоны" и позволить вашей программе закончить, даже если эти потоки все еще работают.

Некоторые справочные материалы, которые могут вас заинтересовать:

Ответ 4

Есть большие ответы на вопрос, но я чувствую, что вопрос о потоках демона по-прежнему не объясняется простым способом. Таким образом, этот ответ относится только к третьему вопросу

"основной поток завершается, когда все потоки не-демона завершаются."

Итак, потоки демона python не являются частью программы Python, если "вся программа Python завершается, когда остаются только потоки демона"?

Если вы думаете о том, что такое демона, обычно это служба. Некоторый код, который работает в бесконечном цикле, который обслуживает запрос, заполняет очереди, принимает соединения и т.д. Его используют другие потоки. Он не имеет никакой цели при запуске сам по себе (в едином процессе).

Таким образом, программа не может дождаться завершения потока демона, потому что этого может не произойти. Python завершит выполнение программы, когда будут выполнены все потоки не-демона. Он также останавливает потоки демона.

Чтобы дождаться, когда поток daemon завершит свою работу, используйте метод join(). daemon_thread.join() заставит Python дождаться потока демона, а затем выйти из него. join() также принимает аргумент тайм-аута.