스레드화에서 join()의 용도는 무엇입니까?
나는 파이썬 스레드화를 공부하다가 우연히 발견했습니다.
작성자는 스레드가 데몬 모드에 있으면 사용해야 한다고 말했습니다.join()
메인 스레드가 종료되기 전에 스레드가 자체적으로 완료될 수 있도록 합니다.
하지만 나는 또한 그가 사용하는 것을 보았습니다.t.join()
그럼에도 불구하고.t
그렇지 않았습니다.daemon
예제 코드는 다음과 같습니다.
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()
제가 때문입니다.
메커니즘을 보여주는 다소 서투른 아스키 아트:그join()
아마도 메인 브라우저에서 호출한 것으로 추정됩니다.다른 스레드로 호출할 수도 있지만 다이어그램을 불필요하게 복잡하게 만들 수도 있습니다.
join
한 - 호출메스트의배레하관야드스랙표치해최레유단위다배니합스치하대에드레위신해기하지게하순대한고하현계를인에지드만은▁---▁of,▁to다니합--배치▁trackc▁theread에▁place▁choose스▁the▁in드▁main▁instead레▁should하▁it▁child▁but▁expressreadalling▁ith▁in위▁thread▁be▁placed▁the▁as▁to대신
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
(만) 주 파이프라인의 실행 흐름과 관련이 있습니다.
예를 들어, 여러 페이지를 동시에 다운로드하여 하나의 큰 페이지로 연결하려는 경우 스레드를 사용하여 동시 다운로드를 시작할 수 있지만, 여러 페이지 중 하나의 페이지를 조립하기 전에 마지막 페이지/스레드가 완료될 때까지 기다려야 합니다.는 럴그때사다니합용다니를 사용합니다.join()
.
서류에서 바로.
가입[가입]스레드가 종료될 때까지 기다립니다.이렇게 하면 join() 메서드가 호출되는 스레드가 정상적으로 종료되거나 처리되지 않은 예외를 통해 종료될 때까지 또는 선택적인 시간 초과가 발생할 때까지 호출 스레드를 차단합니다.
을 낳는 주 합니다.t
그리고.d
을 기다립니다.t
끝날 때까지 끝낼 수 있습니다.
프로그램에서 사용하는 논리에 따라 기본 스레드를 계속하기 전에 스레드가 완료될 때까지 기다리는 것이 좋습니다.
또한 문서에서:
스레드는 "데몬 스레드"로 플래그를 지정할 수 있습니다.이 플래그의 중요성은 데몬 스레드만 남았을 때 전체 파이썬 프로그램이 종료된다는 것입니다.
간단한 예를 들어, 다음과 같습니다.
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
▁the▁for▁explicit다를 기다립니다.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()을 메인 스레드의 "홀드"라고 생각하는 한 가지 방법은 -- 일종의 스레드를 디스레드하고 메인 스레드가 계속되기 전에 메인 스레드에서 순차적으로 실행하는 것입니다.그러면 주 스레드가 앞으로 이동하기 전에 스레드가 완료됩니다.이는 join()을 호출하기 전에 스레드가 이미 완료된 경우에도 괜찮다는 것을 의미합니다. join()을 호출하면 메인 스레드가 즉시 해제됩니다.
사실 방금 메인 스레드가 t.join()으로 이동하기 전에 스레드가 완료될 때까지 d.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"
이 출력이 생성됩니다(인쇄문이 서로 스레드화되는 방식에 주목하십시오).
$ 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()이 완료되기 전에 세 개의 스레드가 모두 완료되고 주 스레드가 계속 이동하여 인쇄를 실행한 다음 t2.join()을 인쇄한 다음 t3.join()을 인쇄합니다.
교정을 환영합니다.저는 또한 스레드화에 익숙하지 않습니다.
(참고: 만약 당신이 관심이 있다면, 저는 드링크봇을 위한 코드를 작성하고 있습니다. 그리고 저는 재료 펌프를 순차적으로 실행하는 것이 아니라 동시에 실행하기 위해 스레드가 필요합니다. 각 음료를 기다리는 시간이 줄어듭니다.)
메서드 join()
join() 메서드가 호출된 스레드가 종료될 때까지 호출 스레드를 차단합니다.
출처: http://docs.python.org/2/library/threading.html
조인 - 프로세스가 완료되거나 종료될 때까지 인터프리터가 대기합니다.
>>> 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
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 is killed, this thread will be killed as well.
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
를 만들 때join(t)
thread 모두에 thread( process는 wait해야 .t
몇 초 후에는 자체 프로세스를 더 진행할 수 있습니다.『 』 『 』 『 』 『 』 『 』 『 』 t
초 대기 시간, 두 하위 스레드 모두 일부 텍스트 인쇄와 같은 작업을 수행해야 합니다.에 t
seconds(초): 비슬롯 스레드가 여전히 작업을 완료하지 못하고 기본 프로세스가 작업을 완료한 후에도 완료할 수 있지만 데몬 스레드의 경우 기회 창을 놓쳤을 뿐입니다.그러나 파이썬 프로그램이 종료된 후에는 결국 소멸됩니다.잘못된 부분이 있으면 수정 부탁드립니다.
메인 스레드(또는 다른 스레드)가 다른 스레드와 결합하는 데는 몇 가지 이유가 있습니다.
스레드가 일부 리소스를 생성하거나 보유(잠금)했을 수 있습니다.조인 호출 스레드가 대신 리소스를 지울 수 있습니다.
join()은 호출된 스레드가 종료된 후에도 조인-스레드 스레드가 계속되도록 하는 자연스러운 차단 호출입니다.
파이썬 프로그램이 다른 스레드에 참여하지 않는 경우에도 파이썬 인터프리터가 대신 비데몬 스레드에 참여합니다.
join()
에서는 비슬롯 스레드와 데몬 스레드가 모두 완료될 때까지 기다립니다.를 사용하지 않으면 비 데몬 스레드가 실행되고 주 스레드와 동시에 완료됩니다.
를 사용하지 않으면 데몬 스레드가 메인 스레드와 동시에 실행되며, 메인 스레드가 완료되면 데몬 스레드가 계속 실행 중이면 데몬 스레드가 완료되지 않고 종료됩니다.
아래 및 (데몬 스레드)와 함께(데몬은 기본값):
import time
from threading import Thread
def test1():
for _ in range(3):
print("Test1 is running...")
time.sleep(1)
print("Test1 is completed")
def test2():
for _ in range(3):
print("Test2 is running...")
time.sleep(1)
print("Test2 is completed")
# Here
thread1 = Thread(target=test1, daemon=False)
thread2 = Thread(target=test2, daemon=False)
# Here
thread1.start()
thread2.start()
thread1.join() # Here
thread2.join() # Here
print("Main is completed")
또는 아래 및 (비 데몬 스레드)와 함께:
# ...
# Here
thread1 = Thread(target=test1, daemon=True)
thread2 = Thread(target=test2, daemon=True)
# Here
# ...
thread1.join() # Here
thread2.join() # Here
print("Main is completed")
join()
그리고 non-discovery 또는 데몬 스레드가 완료될 때까지 기다립니다.따라서 다음과 같이 에 인쇄되고 스레드가 다음과 같이 완료됩니다.
Test1 is running...
Test2 is running...
Test1 is running...
Test2 is running...
Test1 is running...
Test2 is running...
Test1 is completed
Test2 is completed
Main is completed
사용하지 않는 경우 및 아래의 if(비 데몬 스레드):
# ...
# Here
thread1 = Thread(target=test1, daemon=False)
thread2 = Thread(target=test2, daemon=False)
# Here
# ...
# thread1.join()
# thread2.join()
print("Main is completed")
Test1
및 기본 스레드와 동시에 실행되고 완료되는 비-스레드가 동시에 실행됩니다.그래서 아래 그림과 같이 가 인쇄되고 스레드가 완성됩니다.
Test1 is running...
Test2 is running...
Main is completed
Test1 is running...
Test2 is running...
Test1 is running...
Test2 is running...
Test1 is completed
Test2 is completed
사용하지 않는 경우 및 아래의 if(대몬 스레드):
# ...
# Here
thread1 = Thread(target=test1, daemon=True)
thread2 = Thread(target=test2, daemon=True)
# Here
# ...
# thread1.join()
# thread2.join()
print("Main is completed")
Test1
및 데몬 스레드가 메인 스레드와 동시에 실행됩니다.따라서 에 인쇄되어 있고 데몬 스레드가 완료되기 전 및 메인 스레드가 완료되면 아래와 같이 데몬 스레드가 완료되지 않고 다음과 같이 데몬 스레드는 완료되지 않고 종료됩니다.
Test1 is running...
Test2 is running...
Main is completed
여기서는 동기식 처리와 비동기식 처리의 차이를 잘못 이해하고 있는 것 같습니다.
스레드는 하위 절차를 실행하기 위한 것으로, 대부분의 경우 "병렬" 또는 "동시" 방식으로 실행됩니다(장치에 멀티 프로세서가 있는지 여부에 따라 다름).하지만, 동시성에 대한 이유는 무엇입니까?대부분은 "분할 및 정복"이라는 개념을 적용하여 프로세스의 성능을 향상시키는 것입니다.여러 개의 스레드(하위 프로세스)가 전체 프로세스의 "부분"을 동시에 실행하도록 한 다음 모든 하위 프로세스 결과가 결합되는 "최종" 단계를 수행합니다(따라서 "결합" 방법).
물론 효율성을 높이기 위해서는 스레드로 분할된 부분이 "상호 배타적"이어야 합니다(즉, 업데이트할 값을 공유하지 않습니다... -- 병렬 컴퓨팅에서는 "중요 섹션"이라고 함).두 개 이상의 스레드에 의해 업데이트되는 값이 하나 이상 있는 경우, 하나는 다른 하나가 업데이트를 "완료"할 때까지 기다려야 하며, 그렇지 않으면 일관성 없는 결과를 얻어야 합니다(즉, 은행 계좌를 소유하고 있는 두 사람이 현금 자동 인출기에서 특정 금액을 인출하려고 합니다...).두 ATM 기기 모두에서 변수 "잔액"을 "잠금"하거나 "보호"하는 적절한 메커니즘이 없을 경우, 인출은 잔액의 최종 가치를 완전히 망쳐 계좌 소유자에게 명백한 심각한 재정 문제를 야기할 것입니다.
병렬 컴퓨팅에서 스레드의 목적으로 돌아가자면, 모든 스레드가 개별적인 부분을 수행하도록 하고, "결합"을 사용하여 각 개별 결과가 글로벌 결과로 "통합"되도록 기본 프로세스로 "재결합"됩니다.
예를 들면요?그 중 많은 것들이 있지만, 몇 가지만 열거해 보겠습니다.
행렬 곱셈: 행렬 C의 벡터를 얻기 위해 각 스레드에 행렬 A의 벡터 전체를 두 번째 행렬 B로 곱합니다.마지막으로 모든 결과 벡터를 조합하여 결과를 "표시"(표시)하도록 합니다. 행렬 C.이 예에서는 행렬 B가 모든 스레드에서 사용되지만 행렬 B의 값은 업데이트되거나 수정되지 않습니다(읽기 전용).
요약, 방대한 수의 배열(정수든 부동소수든 수천 개의 값 배열)의 곱입니다.부분 합계/제품을 실행할 스레드를 만듭니다(예: 10K 값을 합계해야 하는 경우 각각 2K 값을 포함하여 5개의 스레드를 생성합니다). 그런 다음 "join"을 사용하여 메인 프로세스로 돌아가서 5개 스레드의 개별 결과를 모두 합계하도록 합니다.
이론적으로 이 프로세스는 2000 + 5단계를 수행합니다(2000은 5개 스레드에서 동시에 2000개, 추가로 메인 프로세스에서 최종 5개 하위 합계).그러나 실제로는 5개 스레드가 자체적으로 2000개의 숫자를 합산하는 데 걸리는 시간은 서로 다른 요인(프로세서 속도, 전기 흐름 또는 웹 서비스인 경우, 네트워크 지연 시간 등)에 따라 완전히 달라집니다.그러나 투자된 시간은 "최악의 경우", "가장 느린" 스레드가 걸리는 시간, 그리고 5개의 결과 단계의 최종 합계입니다.또한 실제로 전체 작업의 20%를 수행해야 하는 스레드는 작업의 100%를 수행하는 단일 순차 프로세스보다 훨씬 오래 걸릴 수 있습니다(물론 처리할 샘플의 크기에 따라 다릅니다).10K 값의 합계에서는 동일한 스레드 5개를 사용하여 10개의 값을 합계하는 것과 같은 이점은 없습니다.그것은 실용적이지 않습니다, 그럴 가치가 없습니다).
빠른 정렬:우리 모두는 일반적으로 빠른 정렬이 어떻게 작동하는지 알고 있습니다.하지만, 예를 들어, 우리가 두 개의 스레드로 실행한다면, 그것을 개선할 수 있는 기회가 있습니다. 하나는 홀수를 실행하는 것이고 다른 하나는 짝수를 실행하는 것입니다.그런 다음 재귀적으로 실행되고 어느 시점에서 두 스레드의 결과를 결합하여 두 스레드가 초기 작업을 수행한 후에 숫자가 충분히 정렬되므로 반복 횟수가 많지 않은 방식으로 최종 빠른 정렬을 수행합니다.이는 상당히 많고 순서가 없는 항목의 경우 성능이 크게 향상되는 것입니다.세 개의 스레드는 그 배후에 있는 논리를 어느 정도 조정함으로써 사용될 수 있지만, 그 이득은 정말로 최소이며 프로그래밍할 가치가 없습니다.그러나 두 개의 스레드는 상당한 성능(시간) 이득을 가집니다.
따라서 파이썬에서 "join"을 사용하는 것은 중요한 의미를 가집니다. 하지만 프로그래밍이 무엇을 "paralellization"하고 싶은지, 그리고 메인 프로세스에서 어떤 단계를 유지해야 하는지에 대한 올바른 단계에서 알고리즘을 분할하는 데 얼마나 숙련되었는지 이해하는 것에 따라 많은 부분이 달라집니다.그것은 프로그래밍 "반패턴"보다는 "논리" 사고의 문제입니다.
"join()을 사용하면 무슨 소용이 있습니까?"라고 당신은 말합니다.정말로, 그것은 "프로그램이 종료될 때 파이썬과 OS가 내 파일을 닫아줄 것이기 때문에 파일을 닫아도 무슨 소용이 있습니까?"와 같은 대답입니다.
그것은 단순히 좋은 프로그래밍의 문제입니다.스레드가 더 이상 실행되지 않아야 하는 코드의 지점에서 스레드를 조인()해야 합니다. 스레드가 자신의 코드를 방해하지 않도록 확실히 해야 하거나 더 큰 시스템에서 올바르게 동작하도록 해야 하기 때문입니다.
가입()에 필요한 추가 시간 때문에 "코드가 응답을 지연시키지 않았으면 합니다."라고 말할 수 있습니다.이것은 일부 시나리오에서 완벽하게 유효할 수 있지만, 이제 당신의 코드가 "파이썬과 OS가 정리할 수 있도록 방치"하고 있다는 점을 고려해야 합니다.성능상의 이유로 이 작업을 수행하는 경우 해당 동작을 문서화할 것을 강력히 권장합니다.특히 다른 사용자가 사용할 것으로 예상되는 라이브러리/패키지를 구축하는 경우에는 더욱 그렇습니다.
성능상의 이유 외에는 ()에 가입하지 않을 이유가 없으며, 당신의 코드가 그렇게 잘 수행될 필요는 없다고 주장합니다.
언급URL : https://stackoverflow.com/questions/15085348/what-is-the-use-of-join-in-threading
'sourcecode' 카테고리의 다른 글
다른 사용자의 스키마에 부여된 권한을 확인하는 방법 (0) | 2023.06.27 |
---|---|
Python 패키지의 종속성을 찾는 방법 (0) | 2023.06.27 |
열의 값이 고유한지 확인하기 위한 SQL 쿼리 (0) | 2023.06.27 |
로드에서 현재 사용자를 가져올 수 없습니다. (0) | 2023.06.27 |
OS X "El Capitan"에 보석을 설치할 수 없습니다. (0) | 2023.06.27 |