私はPythonのスレッドを勉強していて、出会った join()
。
スレッドがデーモンモードの場合、メインスレッドが終了する前にスレッドが終了するようにjoin()
を使用する必要があると著者は語っています。
t
がdaemon
ではなかったとしても、私は彼がt.join()
を使っているのを見ました。
サンプルコードはこちら
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()
デーモンではないのでt.join()
を使用しているのかわからないし、削除しても何も変わらない
メカニズムを説明するためのやや不器用なASCIIアート:join()
はおそらくメインスレッドによって呼び出されます。別のスレッドから呼び出すこともできますが、不必要にダイアグラムが複雑になります。
join
-呼び出しはメインスレッドのトラックに配置する必要がありますが、スレッドの関係を表現し、できるだけ単純にするために、代わりに子スレッドに配置します。
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
したがって、変更が見られないのは、メインスレッドがjoin
の後に何もしないためです。 join
はメインスレッドの実行フローに(唯一)関連があると言えます。
たとえば、大量のページを同時にダウンロードしてそれらを1つの大きなページに連結する場合は、スレッドを使用して同時ダウンロードを開始できますが、最後のページまたはスレッドが終了するまで待ってから単一ページを組み立てる必要があります。たくさんあります。それがjoin()
を使う時です。
からまっすぐ docs
join([timeout])スレッドが終了するまで待ちます。これは、join()メソッドが呼び出されたスレッドが終了するまで(通常または未処理の例外によって)、あるいはオプションのタイムアウトが発生するまで、呼び出し元のスレッドをブロックします。
これは、t
とd
を生成するメインスレッドが、終了するまでt
が終了するのを待つことを意味します。
プログラムが採用しているロジックによっては、メインスレッドが継続する前にスレッドが終了するまで待つことをお勧めします。
また、ドキュメントから:
スレッドは「デーモンスレッド」としてフラグを立てることができます。このフラグの意味は、デーモンスレッドだけが残ったときにPythonプログラム全体が終了するということです。
簡単な例として、これがあるとします。
def non_daemon():
time.sleep(5)
print 'Test non-daemon'
t = threading.Thread(name='non-daemon', target=non_daemon)
t.start()
これで終わります:
print 'Test one'
t.join()
print 'Test two'
これは出力されます:
Test one
Test non-daemon
Test two
ここでマスタースレッドは、2回目にt
を呼び出すまで、print
スレッドが終了するのを明示的に待ちます。
あるいは、これがあった場合:
print 'Test one'
print 'Test two'
t.join()
私達はこの出力を得ます:
Test one
Test two
Test non-daemon
ここでメインスレッドで仕事をしてから、t
スレッドが終了するのを待ちます。この場合、明示的に結合しているt.join()
を削除しても、プログラムは暗黙的にt
が終了するのを待ちます。
このスレッドをありがとう - それは私にも大いに役立ちました。
私は今日.join()について何かを学びました。
これらのスレッドは並行して実行されます。
d.start()
t.start()
d.join()
t.join()
これらは順番に実行されます(私が望んでいたものではありません)。
d.start()
d.join()
t.start()
t.join()
特に、私は巧妙で片付けようとしていました:
class Kiki(threading.Thread):
def __init__(self, time):
super(Kiki, self).__init__()
self.time = time
self.start()
self.join()
これはうまくいきます!しかしそれは順次実行されます。 self.start()を__ init __に入れることはできますが、self.join()を置くことはできません。それはしなければなりません後にすべてのスレッドが開始されました。
join()はメインスレッドがあなたのスレッドが終了するのを待つ原因となります。それ以外の場合、あなたのスレッドはすべて単独で実行されます。
そのため、join()をメインスレッドの「保留」と見なす1つの方法 - メインスレッドが続行できるようになる前に、スレッドのスレッドを解除してメインスレッドで順次実行するようなものです。それはメインスレッドが前進する前にあなたのスレッドが完全であることを保証します。これは、join()を呼び出す前にスレッドが既に終了していれば問題ないことを意味します - join()が呼び出されるとメインスレッドはただちに解放されます。
実際、メインスレッドは、スレッドdが終了するまでd.join()で待機してからt.join()に移動するようになりました。
実際、非常に明確にするために、このコードを考えてください。
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"
この出力が生成されます(printステートメントが互いにどのようにスレッド化されているかに注意してください)。
$ 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
$
T1.join()はメインスレッドを保留しています。 t1.join()が終了してメインスレッドがprint、t2.join()、print、t3.join()の順に実行されてからprintが実行される前に、3つのスレッドすべてが完了します。
訂正は大歓迎です。私はスレッドにも慣れていません。
(注:興味がある場合は、DrinkBot用のコードを作成しています。原料ポンプを順番にではなく並行して実行するには、スレッドを実行する必要があります(飲み物を待つ時間が少なくて済みます)。
メソッドjoin()
join()メソッドが呼び出されたスレッドが終了するまで、呼び出し元のスレッドをブロックします。
簡単な理解、
join - インタプリタはあなたのプロセスが完了または終了になるまで待ちます
>>> 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?
結合なし - インタプリタはプロセスが取得するまで待たない終了、
>>> t = Thread(target=sam)
>>> t.start()
started
>>> print 'yes done' #without join interpreter wont wait until process get terminated
yes done
>>> waiting for 10sec
非デーモンスレッドとデーモンスレッドの両方に対してjoin(t)
関数を作成する場合、メインスレッド(またはメインプロセス)はt
秒待ってから、さらに独自のプロセスで作業を進めることができます。 t
秒の待ち時間の間、両方の子スレッドは、テキストの出力など、できることをすべて実行する必要があります。 t
秒後に、非デーモンスレッドがまだそのジョブを終了していない場合、メインプロセスがそのジョブを終了した後もまだ終了できる場合がありますが、デーモンスレッドの場合は、機会ウィンドウを見逃していました。しかし、pythonプログラムが終了した後に最終的に死ぬでしょう。問題がある場合は訂正してください。
Python 3.xでは、join()はメインスレッドとスレッドを結合するために使用されます。つまりjoin()が特定のスレッドに対して使用されると、メインスレッドは結合されたスレッドの実行が完了するまで実行を停止します。
#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!
'''
この例は.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
でる:
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