J'étudiais le filetage du python et suis tombé sur join()
.
L'auteur a dit que si le fil est en mode démon, je dois utiliser join()
pour que le fil puisse se terminer avant le fil principal.
mais je l'ai également vu utiliser t.join()
même si t
n'était pas daemon
exemple de code est-ce
import threading
import time
import logging
logging.basicConfig(level=logging.DEBUG,
format='(%(threadName)-10s) %(message)s',
)
def daemon():
logging.debug('Starting')
time.sleep(2)
logging.debug('Exiting')
d = threading.Thread(name='daemon', target=daemon)
d.setDaemon(True)
def non_daemon():
logging.debug('Starting')
logging.debug('Exiting')
t = threading.Thread(name='non-daemon', target=non_daemon)
d.start()
t.start()
d.join()
t.join()
je ne sais pas quelle est l'utilisation de t.join()
car ce n'est pas un démon et je ne vois aucun changement, même si je l'enlève
Un art ascii un peu maladroit pour démontrer le mécanisme: La join()
est probablement appelée par le thread principal. Il pourrait également être appelé par un autre thread, mais compliquerait inutilement le diagramme.
join
- call devrait être placé dans la piste du thread principal, mais pour exprimer la relation de thread et la garder aussi simple que possible, je choisis de le placer dans le thread enfant.
without join:
+---+---+------------------ main-thread
| |
| +........... child-thread(short)
+.................................. child-thread(long)
with join
+---+---+------------------***********+### main-thread
| | |
| +...........join() | child-thread(short)
+......................join()...... child-thread(long)
with join and daemon thread
+-+--+---+------------------***********+### parent-thread
| | | |
| | +...........join() | child-thread(short)
| +......................join()...... child-thread(long)
+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, child-thread(long + daemonized)
'-' main-thread/parent-thread/main-program execution
'.' child-thread execution
'#' optional parent-thread execution after join()-blocked parent-thread could
continue
'*' main-thread 'sleeping' in join-method, waiting for child-thread to finish
',' daemonized thread - 'ignores' lifetime of other threads;
terminates when main-programs exits; is normally meant for
join-independent tasks
Donc, la raison pour laquelle vous ne voyez aucun changement est que votre thread principal ne fait rien après votre join
. Vous pouvez dire que join
est (uniquement) pertinent pour le flux d'exécution du thread principal.
Si, par exemple, vous souhaitez télécharger simultanément plusieurs pages pour les concaténer dans une seule page volumineuse, vous pouvez démarrer les téléchargements simultanés à l'aide de threads, mais vous devez attendre que la dernière page/thread soit terminée avant de commencer à assembler une seule page. sur beaucoup. C'est à ce moment que vous utilisez join()
.
Directement des docs
rejoindre ([timeout]) Attendez que le thread se termine. Cela bloque le thread appelant jusqu'à ce que le thread dont la méthode join () est appelée se termine - normalement ou via une exception non gérée - ou jusqu'à ce que le délai d'expiration facultatif se produise.
Cela signifie que le thread principal qui génère t
et d
attend que t
se termine jusqu'à ce qu'il se termine.
En fonction de la logique utilisée par votre programme, vous souhaiterez peut-être attendre la fin d'un thread avant que votre thread principal ne continue.
Aussi de la documentation:
Un fil peut être marqué en tant que «fil démon». La signification de cet indicateur est que l'ensemble du programme Python se ferme lorsqu'il ne reste plus que des threads de démon.
Un exemple simple, disons que nous avons ceci:
def non_daemon():
time.sleep(5)
print 'Test non-daemon'
t = threading.Thread(name='non-daemon', target=non_daemon)
t.start()
Qui se termine avec:
print 'Test one'
t.join()
print 'Test two'
Cela produira:
Test one
Test non-daemon
Test two
Ici, le thread principal attend explicitement que le thread t
se termine jusqu'à ce qu'il appelle print
la deuxième fois.
Alternativement si nous avions ceci:
print 'Test one'
print 'Test two'
t.join()
Nous aurons cette sortie:
Test one
Test two
Test non-daemon
Ici, nous faisons notre travail dans le thread principal, puis nous attendons que le thread t
soit terminé. Dans ce cas, nous pourrions même supprimer la jonction explicite t.join()
et le programme attendra implicitement que t
se termine.
Merci pour ce fil - cela m'a beaucoup aidé aussi.
J'ai appris quelque chose à propos de .join () aujourd'hui.
Ces threads fonctionnent en parallèle:
d.start()
t.start()
d.join()
t.join()
et ceux-ci fonctionnent séquentiellement (pas ce que je voulais):
d.start()
d.join()
t.start()
t.join()
En particulier, j’essayais d’être intelligent et bien rangé:
class Kiki(threading.Thread):
def __init__(self, time):
super(Kiki, self).__init__()
self.time = time
self.start()
self.join()
Cela marche! Mais cela fonctionne séquentiellement. Je peux mettre self.start () dans __ init __, mais pas self.join (). Cela doit être fait après chaque thread a été démarré.
join () est ce qui fait que le thread principal attend que votre thread se termine. Sinon, votre fil s'exécute tout seul.
Donc, une façon de penser à join () en tant que "maintien" sur le thread principal - en quelque sorte, le thread est dés-threadé et exécuté séquentiellement dans le thread principal, avant que le thread principal puisse continuer. Cela garantit que votre thread est terminé avant que le thread principal ne progresse. Notez que cela signifie que le processus est terminé si votre thread est déjà terminé avant d'appeler join () - le thread principal est simplement libéré immédiatement lorsque join () est appelé.
En fait, il me semble tout à l'heure que le thread principal attend à d.join () jusqu'à ce que le thread d se termine avant de passer à t.join ().
En fait, pour être très clair, considérons ce code:
import threading
import time
class Kiki(threading.Thread):
def __init__(self, time):
super(Kiki, self).__init__()
self.time = time
self.start()
def run(self):
print self.time, " seconds start!"
for i in range(0,self.time):
time.sleep(1)
print "1 sec of ", self.time
print self.time, " seconds finished!"
t1 = Kiki(3)
t2 = Kiki(2)
t3 = Kiki(1)
t1.join()
print "t1.join() finished"
t2.join()
print "t2.join() finished"
t3.join()
print "t3.join() finished"
Il produit cette sortie (notez comment les instructions d'impression sont liées les unes aux autres).
$ python test_thread.py
32 seconds start! seconds start!1
seconds start!
1 sec of 1
1 sec of 1 seconds finished!
21 sec of
3
1 sec of 3
1 sec of 2
2 seconds finished!
1 sec of 3
3 seconds finished!
t1.join() finished
t2.join() finished
t3.join() finished
$
Le t1.join () tient le fil principal. Les trois threads sont terminés avant la fin de t1.join () et le thread principal continue d'exécuter l'impression, puis t2.join () puis print, puis t3.join (), puis print.
Les corrections sont les bienvenues. Je suis aussi nouveau dans le filetage.
(Remarque: au cas où cela vous intéresserait, j'écris le code d'un DrinkBot et j'ai besoin de fileter pour faire fonctionner les pompes d'ingrédients simultanément plutôt que de façon séquentielle - moins de temps d'attente pour chaque boisson.)
La méthode join ()
bloque le thread appelant jusqu'à ce que le thread dont la méthode join () est appelée soit terminé.
Lors de la création de la fonction join(t)
pour les threads non démon et les démons, le thread principal (ou le processus principal) doit attendre t
secondes, puis peut aller plus loin pour travailler sur son propre processus. Pendant le délai d'attente de t
secondes, les deux fils enfants doivent faire ce qu'ils peuvent, par exemple imprimer du texte. Après t
secondes, si le thread non-démon n'a toujours pas terminé son travail et qu'il peut le terminer après le processus principal, mais pour le démon, il a juste manqué sa fenêtre d'opportunité. Cependant, il mourra éventuellement après la fermeture du programme python. S'il vous plaît, corrigez-moi si quelque chose ne va pas.
Simple comprendre,
with join - interpreter attendra que votre processus obtienne complete ou terminé
>>> from threading import Thread
>>> import time
>>> def sam():
... print 'started'
... time.sleep(10)
... print 'waiting for 10sec'
...
>>> t = Thread(target=sam)
>>> t.start()
started
>>> t.join() # with join interpreter will wait until your process get completed or terminated
done? # this line printed after thread execution stopped i.e after 10sec
waiting for 10sec
>>> done?
sans jointure - l'interprète n'attendra pas que le processus obtienne terminé ,
>>> t = Thread(target=sam)
>>> t.start()
started
>>> print 'yes done' #without join interpreter wont wait until process get terminated
yes done
>>> waiting for 10sec
Cet exemple illustre l'action .join()
:
import threading
import time
def threaded_worker():
for r in range(10):
print('Other: ', r)
time.sleep(2)
thread_ = threading.Timer(1, threaded_worker)
thread_.daemon = True # If the main thread kills, this thread will be killed too.
thread_.start()
flag = True
for i in range(10):
print('Main: ', i)
time.sleep(2)
if flag and i > 4:
print(
'''
Threaded_worker() joined to the main thread.
Now we have a sequential behavior instead of concurrency.
''')
thread_.join()
flag = False
En dehors:
Main: 0
Other: 0
Main: 1
Other: 1
Main: 2
Other: 2
Main: 3
Other: 3
Main: 4
Other: 4
Main: 5
Other: 5
Threaded_worker() joined to the main thread.
Now we have a sequential behavior instead of concurrency.
Other: 6
Other: 7
Other: 8
Other: 9
Main: 6
Main: 7
Main: 8
Main: 9
Dans python 3.x, join () est utilisé pour joindre un fil au fil principal, c'est-à-dire que lorsque join () est utilisé pour un fil particulier, le fil principal cesse de s'exécuter jusqu'à ce que l'exécution du fil joint soit terminée.
#1 - Without Join():
import threading
import time
def loiter():
print('You are loitering!')
time.sleep(5)
print('You are not loitering anymore!')
t1 = threading.Thread(target = loiter)
t1.start()
print('Hey, I do not want to loiter!')
'''
Output without join()-->
You are loitering!
Hey, I do not want to loiter!
You are not loitering anymore! #After 5 seconds --> This statement will be printed
'''
#2 - With Join():
import threading
import time
def loiter():
print('You are loitering!')
time.sleep(5)
print('You are not loitering anymore!')
t1 = threading.Thread(target = loiter)
t1.start()
t1.join()
print('Hey, I do not want to loiter!')
'''
Output with join() -->
You are loitering!
You are not loitering anymore! #After 5 seconds --> This statement will be printed
Hey, I do not want to loiter!
'''