logo

파이썬 | 스레드를 죽이는 다양한 방법

일반적으로 스레드를 갑자기 종료하는 것은 나쁜 프로그래밍 관행으로 간주됩니다. 스레드를 갑자기 종료하면 적절하게 닫아야 하는 중요한 리소스가 열려 있을 수 있습니다. 그러나 특정 기간이 경과하거나 일부 인터럽트가 생성되면 스레드를 종료하고 싶을 수도 있습니다. Python에서 스레드를 종료할 수 있는 다양한 방법이 있습니다.

  • Python 스레드에서 예외 발생
  • 정지 플래그 설정/리셋
  • 추적을 사용하여 스레드 종료
  • 멀티프로세싱 모듈을 사용하여 스레드 종료
  • Python 스레드를 데몬으로 설정하여 종료
  • 숨겨진 함수 _stop() 사용하기

Python 스레드에서 예외 발생:
이 방법은 다음 기능을 사용합니다. PyThreadState_SetAsyncExc() 스레드에서 예외를 발생시킵니다. 예를 들어,



파이썬3








# Python program raising> # exceptions in a python> # thread> import> threading> import> ctypes> import> time> > class> thread_with_exception(threading.Thread):> >def> __init__(>self>, name):> >threading.Thread.__init__(>self>)> >self>.name>=> name> > >def> run(>self>):> ># target function of the thread class> >try>:> >while> True>:> >print>(>'running '> +> self>.name)> >finally>:> >print>(>'ended'>)> > >def> get_id(>self>):> ># returns id of the respective thread> >if> hasattr>(>self>,>'_thread_id'>):> >return> self>._thread_id> >for> id>, thread>in> threading._active.items():> >if> thread>is> self>:> >return> id> > >def> raise_exception(>self>):> >thread_id>=> self>.get_id()> >res>=> ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,> >ctypes.py_object(SystemExit))> >if> res>>1>:> >ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,>0>)> >print>(>'Exception raise failure'>)> > t1>=> thread_with_exception(>'Thread 1'>)> t1.start()> time.sleep(>2>)> t1.raise_exception()> t1.join()>

>

>

위의 코드를 기계에서 실행하면 raise_Exception() 함수가 호출되자마자 대상 함수 run()이 종료된다는 것을 알 수 있습니다. 이는 예외가 발생하자마자 프로그램 제어가 try 블록에서 벗어나고 run() 함수가 종료되기 때문입니다. 그런 다음 Join() 함수를 호출하여 스레드를 종료할 수 있습니다. run_Exception() 함수가 없으면 대상 함수 run()은 계속 실행되고 Join() 함수는 스레드를 종료하기 위해 호출되지 않습니다.

정지 플래그 설정/리셋:
스레드를 종료하기 위해 중지 플래그를 선언할 수 있으며 이 플래그는 스레드에 의해 가끔 확인됩니다. 예를 들어

파이썬3




# Python program showing> # how to kill threads> # using set/reset stop> # flag> import> threading> import> time> def> run():> >while> True>:> >print>(>'thread running'>)> >global> stop_threads> >if> stop_threads:> >break> stop_threads>=> False> t1>=> threading.Thread(target>=> run)> t1.start()> time.sleep(>1>)> stop_threads>=> True> t1.join()> print>(>'thread killed'>)>

>

>

위 코드에서는 전역 변수 stop_threads가 설정되자마자 대상 함수 run()이 종료되고 t1.join()을 사용하여 스레드 t1을 종료할 수 있습니다. 그러나 어떤 이유로 인해 전역 변수 사용을 자제할 수도 있습니다. 이러한 상황에서는 함수 개체를 전달하여 아래와 같이 유사한 기능을 제공할 수 있습니다.

파이썬3




# Python program killing> # threads using stop> # flag> import> threading> import> time> def> run(stop):> >while> True>:> >print>(>'thread running'>)> >if> stop():> >break> > def> main():> >stop_threads>=> False> >t1>=> threading.Thread(target>=> run, args>=>(>lambda> : stop_threads, ))> >t1.start()> >time.sleep(>1>)> >stop_threads>=> True> >t1.join()> >print>(>'thread killed'>)> main()>

>

>

위 코드에 전달된 함수 개체는 항상 지역 변수 stop_threads의 값을 반환합니다. 이 값은 run() 함수에서 확인되며, stop_threads가 재설정되자마자 run() 함수가 종료되고 스레드가 종료될 수 있습니다.

추적을 사용하여 스레드 종료:
이 방법은 다음을 설치하여 작동합니다. 흔적 각 스레드에서. 각 추적은 일부 자극이나 플래그가 감지되면 자체적으로 종료되므로 관련 스레드가 즉시 종료됩니다. 예를 들어

데이터 프레임을 만드는 팬더

파이썬3




# Python program using> # traces to kill threads> import> sys> import> trace> import> threading> import> time> class> thread_with_trace(threading.Thread):> >def> __init__(>self>,>*>args,>*>*>keywords):> >threading.Thread.__init__(>self>,>*>args,>*>*>keywords)> >self>.killed>=> False> >def> start(>self>):> >self>.__run_backup>=> self>.run> >self>.run>=> self>.__run> >threading.Thread.start(>self>)> >def> __run(>self>):> >sys.settrace(>self>.globaltrace)> >self>.__run_backup()> >self>.run>=> self>.__run_backup> >def> globaltrace(>self>, frame, event, arg):> >if> event>=>=> 'call'>:> >return> self>.localtrace> >else>:> >return> None> >def> localtrace(>self>, frame, event, arg):> >if> self>.killed:> >if> event>=>=> 'line'>:> >raise> SystemExit()> >return> self>.localtrace> >def> kill(>self>):> >self>.killed>=> True> def> func():> >while> True>:> >print>(>'thread running'>)> t1>=> thread_with_trace(target>=> func)> t1.start()> time.sleep(>2>)> t1.kill()> t1.join()> if> not> t1.isAlive():> >print>(>'thread killed'>)>

>

>

이 코드에서 start()는 다음을 사용하여 시스템 추적 기능을 설정하도록 약간 수정되었습니다. 세트트레이스() . 로컬 추적 함수는 각 스레드의 종료 플래그(killed)가 설정될 때마다 다음 코드 줄 실행 시 SystemExit 예외가 발생하여 대상 함수 func의 실행이 종료되도록 정의됩니다. 이제 스레드는 Join()을 사용하여 종료될 수 있습니다.

멀티프로세싱 모듈을 사용하여 스레드 종료:
Python의 다중 처리 모듈을 사용하면 스레딩 모듈을 사용하여 스레드를 생성하는 것과 유사한 방식으로 프로세스를 생성할 수 있습니다. 멀티스레딩 모듈의 인터페이스는 스레딩 모듈의 인터페이스와 유사합니다. 예를 들어, 주어진 코드에서 우리는 1부터 9까지 세는 세 개의 스레드(프로세스)를 만들었습니다.

파이썬3

VLC를 사용하여 YouTube 동영상 다운로드




# Python program creating> # three threads> import> threading> import> time> # counts from 1 to 9> def> func(number):> >for> i>in> range>(>1>,>10>):> >time.sleep(>0.01>)> >print>(>'Thread '> +> str>(number)>+> ': prints '> +> str>(number>*>i))> # creates 3 threads> for> i>in> range>(>0>,>3>):> >thread>=> threading.Thread(target>=>func, args>=>(i,))> >thread.start()>

>

>

위 코드의 기능은 거의 변경하지 않고 비슷한 방식으로 multiprocessing 모듈을 사용하여 구현할 수도 있습니다. 아래에 제공된 코드를 참조하세요.

파이썬3




# Python program creating> # thread using multiprocessing> # module> import> multiprocessing> import> time> def> func(number):> >for> i>in> range>(>1>,>10>):> >time.sleep(>0.01>)> >print>(>'Processing '> +> str>(number)>+> ': prints '> +> str>(number>*>i))> for> i>in> range>(>0>,>3>):> >process>=> multiprocessing.Process(target>=>func, args>=>(i,))> >process.start()>

>

>

두 모듈의 인터페이스는 유사하지만 두 모듈의 구현은 매우 다릅니다. 모든 스레드는 전역 변수를 공유하는 반면 프로세스는 서로 완전히 분리되어 있습니다. 따라서 프로세스 종료는 스레드 종료에 비해 훨씬 안전합니다. Process 클래스에는 다음과 같은 메소드가 제공됩니다. 끝내다() , 프로세스를 종료합니다. 이제 초기 문제로 돌아갑니다. 위 코드에서 0.03초가 지난 후 모든 프로세스를 종료하고 싶다고 가정해 보겠습니다. 이 기능은 다음 코드의 multiprocessing 모듈을 사용하여 구현됩니다.

파이썬3




# Python program killing> # a thread using multiprocessing> # module> import> multiprocessing> import> time> def> func(number):> >for> i>in> range>(>1>,>10>):> >time.sleep(>0.01>)> >print>(>'Processing '> +> str>(number)>+> ': prints '> +> str>(number>*>i))> # list of all processes, so that they can be killed afterwards> all_processes>=> []> for> i>in> range>(>0>,>3>):> >process>=> multiprocessing.Process(target>=>func, args>=>(i,))> >process.start()> >all_processes.append(process)> # kill all processes after 0.03s> time.sleep(>0.03>)> for> process>in> all_processes:> >process.terminate()>

>

>

두 모듈의 구현은 서로 다릅니다. 위 코드의 multiprocessing 모듈이 제공하는 이 기능은 스레드 종료와 유사합니다. 따라서 멀티프로세싱 모듈은 간단한 모듈로 사용될 수 있습니다. 대안 Python에서 스레드 종료를 구현해야 할 때마다.

Python 스레드를 데몬으로 설정하여 종료합니다.
데몬 스레드 메인 프로그램이 종료될 때 종료되는 스레드입니다. 예를 들어

파이썬3




import> threading> import> time> import> sys> def> func():> >while> True>:> >time.sleep(>0.5>)> >print>(>'Thread alive, and it won't die on program termination'>)> t1>=> threading.Thread(target>=>func)> t1.start()> time.sleep(>2>)> sys.exit()>

>

>

스레드 t1은 활성 상태로 유지되며 sys.exit()를 통해 기본 프로그램이 종료되는 것을 방지합니다. Python에서는 데몬이 아닌 살아있는 스레드가 기본 프로그램 종료를 차단합니다. 반면 데몬 스레드 자체는 주 프로그램이 종료되자마자 종료됩니다. 즉, 메인 프로그램이 종료되자마자 모든 데몬 스레드가 종료됩니다. 스레드를 데몬으로 선언하려면 키워드 인수 daemon을 True로 설정합니다. 예를 들어 주어진 코드에서는 데몬 스레드의 속성을 보여줍니다.

파이썬3




# Python program killing> # thread using daemon> import> threading> import> time> import> sys> def> func():> >while> True>:> >time.sleep(>0.5>)> >print>(>'Thread alive, but it will die on program termination'>)> t1>=> threading.Thread(target>=>func)> t1.daemon>=> True> t1.start()> time.sleep(>2>)> sys.exit()>

>

>

주 프로그램이 종료되자마자 스레드 t1이 종료된다는 점에 유의하십시오. 이 방법은 프로그램 종료를 사용하여 스레드 종료를 트리거할 수 있는 경우 매우 유용한 것으로 입증되었습니다. Python에서는 살아있는 데몬 스레드 수에 관계없이 데몬이 아닌 모든 스레드가 죽자마자 기본 프로그램이 종료됩니다. 따라서 열린 파일, 데이터베이스 트랜잭션 등과 같이 이러한 데몬 스레드가 보유한 리소스가 제대로 해제되지 않을 수 있습니다. Python 프로그램의 초기 제어 스레드는 데몬 스레드가 아닙니다. 스레드를 강제로 종료하는 것은 누수나 교착 상태가 발생하지 않는다는 것이 확실하게 알려진 경우가 아니면 권장되지 않습니다.
숨겨진 함수 _stop() 사용:
스레드를 종료하기 위해 숨겨진 함수 _stop()을 사용합니다. 이 함수는 문서화되어 있지 않지만 다음 버전의 Python에서는 사라질 수 있습니다.

파이썬3




# Python program killing> # a thread using ._stop()> # function> import> time> import> threading> class> MyThread(threading.Thread):> ># Thread class with a _stop() method.> ># The thread itself has to check> ># regularly for the stopped() condition.> >def> __init__(>self>,>*>args,>*>*>kwargs):> >super>(MyThread,>self>).__init__(>*>args,>*>*>kwargs)> >self>._stop>=> threading.Event()> ># function using _stop function> >def> stop(>self>):> >self>._stop.>set>()> >def> stopped(>self>):> >return> self>._stop.isSet()> >def> run(>self>):> >while> True>:> >if> self>.stopped():> >return> >print>(>'Hello, world!'>)> >time.sleep(>1>)> t1>=> MyThread()> t1.start()> time.sleep(>5>)> t1.stop()> t1.join()>

이미지가 포함된 마크다운
>

>

메모: Python은 스레드를 종료하는 직접적인 방법을 제공하지 않기 때문에 어떤 상황에서는 위의 방법이 작동하지 않을 수 있습니다.