Explicação de threads daemon

237

Na documentação do Python , diz:

Um encadeamento pode ser sinalizado como um "encadeamento daemon". O significado desse sinalizador é que todo o programa Python sai quando apenas os threads do daemon são deixados. O valor inicial é herdado do encadeamento de criação.

Alguém tem uma explicação mais clara do que isso significa ou um exemplo prático mostrando onde você definiria os threads daemonic?

Esclareça isso para mim: então a única situação em que você não definiria threads daemonicé quando você deseja que eles continuem em execução após a saída do thread principal?

Corey Goldberg
fonte

Respostas:

448

Alguns threads realizam tarefas em segundo plano, como o envio de pacotes keepalive, ou a coleta periódica de lixo, ou o que for. Eles são úteis apenas quando o programa principal está em execução e não há problema em eliminá-los quando os outros threads, que não são daemon, tiverem saído.

Sem os threads do daemon, você teria que acompanhá-los e pedir para eles saírem, antes que seu programa possa sair completamente. Ao defini-los como threads do daemon, você pode deixá-los executar e esquecê-los e, quando seu programa é encerrado, todos os threads do daemon são eliminados automaticamente.

Chris Jester-Young
fonte
1
Portanto, se eu tiver um encadeamento filho que esteja executando uma operação de gravação de arquivo definida como não-deamon, isso significa que tenho que fazê-lo sair explicitamente?
ciasto Piekarz
8
@san O que o seu thread de gravador faz depois de terminar de escrever? Apenas retorna? Se assim for, isso é suficiente. Threads de daemon geralmente são para coisas que são executadas em um loop e não saem por conta própria.
Chris Jester-Young
Ele não fazer nada, nem retorna, seu único propósito de realizar operação de arquivo de gravação
ciasto Piekarz
2
@san Se cair na parte inferior da função do thread, ele retornará implicitamente.
Chris Jester-Young
Ele retorna Nonenesse caso, mas não importa, o valor de retorno não é usado.
Chris Jester-Young
30

Digamos que você esteja criando algum tipo de widget de painel. Como parte disso, você deseja que ele exiba a contagem de mensagens não lidas na sua caixa de e-mail. Então você faz um pequeno tópico que irá:

  1. Conecte-se ao servidor de correio e pergunte quantas mensagens não lidas você possui.
  2. Sinalize a GUI com a contagem atualizada.
  3. Durma um pouco.

Quando o widget é iniciado, ele cria esse encadeamento, designa um daemon e o inicia. Por ser um daemon, você não precisa pensar sobre isso; quando o widget sair, o encadeamento será interrompido automaticamente.

John Fouhy
fonte
18

Outros pôsteres deram alguns exemplos de situações nas quais você usaria threads daemon. Minha recomendação, no entanto, é nunca usá-los.

Não é porque eles não são úteis, mas porque existem alguns efeitos colaterais ruins que você pode experimentar se os usar. Os encadeamentos do daemon ainda podem ser executados após o tempo de execução do Python começar a destruir as coisas no encadeamento principal, causando algumas exceções bastante bizarras.

Mais informações aqui:

https://joeshaw.org/python-daemon-threads-considered-harmful/

https://mail.python.org/pipermail/python-list/2005-February/343697.html

Estritamente falando, você nunca precisa deles, apenas facilita a implementação em alguns casos.

Joe Shaw
fonte
Ainda esse problema com python 3? Não há informações claras sobre essas "exceções bizarras" na documentação.
21411 kheraud
5
Na postagem do blog de Joe: "Atualização em junho de 2015: este é o bug do Python 1856. Foi corrigido no Python 3.2.1 e 3.3, mas a correção nunca foi suportada para 2.x. (Uma tentativa de fazer o backport para a ramificação 2.7 causou outro bug e foi abandonado.) Os encadeamentos do daemon podem estar ok no Python> = 3.2.1, mas definitivamente não estão nas versões anteriores. "
clacke
Gostaria de compartilhar aqui minha experiência: tive uma função gerada como Thread várias vezes. Dentro dele, eu tinha uma instância do Python logginge esperava que, após o término do thread, todos os objetos (descritores de arquivo para cada thread / função) fossem destruídos. No final do meu programa, vi muitas saídas como IOError: [Errno 24] Too many open files:. Com lsof -p pid_of_program, descobri que os FDs estavam abertos, ainda que os Thread / Functions terminassem seus trabalhos. Gambiarra? Removendo o manipulador de log no final da função. Então daemonicThreads, não são
dignos de
17

Uma maneira mais simples de pensar sobre isso, talvez: quando o retorno principal, seu processo não será encerrado se ainda houver threads que não sejam daemon em execução.

Um conselho: o desligamento limpo é fácil de se errar quando estão envolvidos threads e sincronização - se você puder evitá-lo, faça-o. Use threads daemon sempre que possível.

Jonathan
fonte
13

Chris já explicou o que são os threads do daemon, então vamos falar sobre o uso prático. Muitas implementações de conjuntos de encadeamentos usam encadeamentos daemon para trabalhadores de tarefas. Trabalhadores são threads que executam tarefas da fila de tarefas.

O trabalhador precisa continuar aguardando tarefas na fila de tarefas indefinidamente, pois não sabe quando a nova tarefa será exibida. O segmento que atribui tarefas (por exemplo, o segmento principal) sabe apenas quando as tarefas terminam. O encadeamento principal espera na fila de tarefas para ficar vazio e sai. Se os trabalhadores forem threads de usuário, ou seja, não daemon, o programa não será encerrado. Ele continuará esperando por esses trabalhadores em execução indefinidamente, mesmo que os trabalhadores não estejam fazendo nada de útil. Marque os threads do daemon dos trabalhadores e o thread principal cuidará de matá-los assim que terminar de manipular tarefas.

Amit
fonte
4
Cuidado com isso! Se um programa envia uma tarefa importante (por exemplo, atualizar algum arquivo "em segundo plano") para uma fila de tarefas daemon, existe o risco de o programa terminar antes de executar a tarefa, ou pior, no meio da atualização do arquivo.
Solomon Slow
10

Citando Chris: "... quando seu programa é encerrado, qualquer encadeamento de daemon é eliminado automaticamente.". Eu acho que isso resume tudo. Você deve ter cuidado ao usá-los, pois eles terminam abruptamente quando o programa principal é executado até a conclusão.

Graves
fonte
4

Quando o seu segundo encadeamento não é Daemon, o encadeamento principal principal do aplicativo não pode ser encerrado porque seus critérios de saída estão sendo vinculados à saída também de encadeamentos não-Daemon. Os encadeamentos não podem ser eliminados à força em python; portanto, seu aplicativo precisará realmente aguardar o término dos encadeamentos que não sejam do Daemon. Se esse comportamento não for o que você deseja, defina seu segundo encadeamento como daemon para que ele não impeça a saída do aplicativo.

truthadjustr
fonte