python 스 레 드 를 강제 적 으로 죽 이지 마 세 요.

6893 단어 python스 레 드
선언:
    python 스 레 드 를 강제 적 으로 죽 이려 고 하지 마 세 요.이것 은 서비스 디자인 에 있어 서 이성 에 맞지 않 습 니 다.다 중 스 레 드 는 작업 의 협력 과 병행 에 사 용 됩 니 다.강제 적 인 수단 으로 스 레 드 를 제거 하면 예상 치 못 한 bug 가 발생 할 확률 이 높 습 니 다.  한 가지 만 기억 하 세 요.잠 금 자원 은 스 레 드 가 종료 되 었 기 때문에 잠 금 자원 을 방출 하지 않 습 니 다!
우 리 는 두 가지 흔히 볼 수 있 는 예 를 들 수 있다.
1.A 라인 이 자 물 쇠 를 가 져 왔 습 니 다.그 는 강제 적 으로 제거 되 었 기 때문에 제때에 release()에서 자 물 쇠 를 방출 하지 못 했 습 니 다.그러면 모든 라인 이 자원 을 가 져 오 는 것 이 막 혔 습 니 다.이것 이 바로 전형 적 인 자물쇠 장면 입 니 다.
2.흔히 볼 수 있 는 생산 소비자 의 장면 에서 소비 자 는 미 션 대기 열 에서 임 무 를 얻 지만 해 킹 당 한 후에 하고 있 는 임 무 를 대기 열 에 잃 어 버 리 지 않 으 면 데이터 가 손실 된다.
다음은 자바 와 python 이 스 레 드 를 종료 하 는 방법 입 니 다.
자바 는 스 레 드 를 종료 할 수 있 는 세 가지 방법 이 있 습 니 다.
1.종료 표 지 를 사용 하여 스 레 드 를 정상적으로 종료 합 니 다.즉,run 방법 이 완 료 된 후에 스 레 드 가 종 료 됩 니 다.
2.stop 방법 을 사용 하여 스 레 드 를 강제로 종료 합 니 다(사용 을 추천 하지 않 습 니 다.stop 은 suspend,resume 과 마찬가지 로 예측 할 수 없 는 결과 가 발생 할 수 있 기 때 문 입 니 다).
3.interrupt 방법 으로 스 레 드 를 중단 합 니 다.
python 은 두 가지 방법 이 있 습 니 다.
1.태그 끝내기
2.ctypes 를 사용 하여 스 레 드 를 강제로 죽 입 니 다.
python 이 든 자바 환경 이 든 이상 적 인 스 레 드 종료 방법 은 스 레 드 를 스스로 자살 시 키 는 것 입 니 다.스 레 드 자살 이란 바로 당신 이 그 에 게 표지 판 을 주 는 것 입 니 다.그 는 스 레 드 에서 물 러 납 니 다.
다음은 python 스 레 드 를 정지 하 는 이상 상황 을 여러 가지 방법 으로 테스트 할 것 입 니 다.우 리 는 프로 세 스 의 모든 실행 스 레 드 를 봅 니 다.  프로 세 스 는 자원 을 제어 한 적 이 있 습 니 다.스 레 드 는 스케줄 러 로 사 용 됩 니 다.프로 세 스 가 실행 되 려 면 스 레 드 가 있어 야 합 니 다.기본 스 레 드 는 프로 세 스 의 pid 와 같 습 니 다.

ps -mp 31449 -o THREAD,tid
 
USER   %CPU PRI SCNT WCHAN USER SYSTEM  TID
root   0.0  -  - -     -   -   -
root   0.0 19  - poll_s  -   - 31449
root   0.0 19  - poll_s  -   - 31450

프로 세 스 의 모든 스 레 드 를 가 져 온 후,strace 를 통 해 31450 이 kill 이 필요 한 스 레 드 id 라 는 것 을 알 게 되 었 습 니 다.kill 이 필요 할 때 전체 프로 세 스 가 무 너 지 는 상황 이 발생 합 니 다.다 중 스 레 드 환경 에서 발생 하 는 신 호 는 전체 프로 세 스에 전달 되 는 것 입 니 다.일반적으로 모든 스 레 드 는 이 신 호 를 받 을 기회 가 있 습 니 다.프로 세 스 는 신 호 를 받 은 스 레 드 컨 텍스트 에서 신호 처리 함 수 를 실행 합 니 다.구체 적 으로 어떤 스 레 드 가 실행 되 는 지 알 수 없습니다.즉,신 호 는 이 프로 세 스 의 스 레 드 를 무 작위 로 보 내 는 것 이다.

strace -p <span style="font-size:14px;line-height:21px;">31450</span> Process <span style="font-size:14px;line-height:21px;">31450</span> attached - interrupt to quit
select(0, NULL, NULL, NULL, {0, 320326}) = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0})   = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0})   = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0})   = ? ERESTARTNOHAND (To be restarted)
--- SIGTERM (Terminated) @ 0 (0) ---
Process <span style="font-size:14px;line-height:21px;">31450</span> detached



위 에 나타 난 문 제 는 사실 pthread 의 설명 과 일치 합 니 다.python 코드 에 signal 신호 처리 함 수 를 추가 한 후에 리 셋 함 수 는 전체 프로 세 스 의 종 료 를 방지 할 수 있 습 니 다.그러면 문제 가 발생 했 습 니 다.신호 함 수 를 통 해 어떤 스 레 드 를 제거 해 야 하 는 지 식별 할 수 없습니다.즉,특정한 스 레 드 를 정확하게 제거 할 수 없습니다.당신 은 신 호 를 31450 스 레 드 id 에 보 냈 지만 신호 수리 자 는 소속 프로 세 스 의 모든 것 입 니 다.또한 신호 처리 함수 에 전 달 된 매개 변 수 는 신호 수 와 신호 stack 일 뿐 있 으 나 마 나 합 니 다.
신호 처 리 를 추가 하면 프로 세 스 를 종료 하지 않 습 니 다.

select(0, NULL, NULL, NULL, {1, 0})   = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0})   = ? ERESTARTNOHAND (To be restarted)
--- SIGTERM (Terminated) @ 0 (0) ---
rt_sigreturn(0xffffffff)        = -1 EINTR (Interrupted system call)
select(0, NULL, NULL, NULL, {1, 0})   = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0})   = 0 (Timeout)
외부 알림 에서 특정한 스 레 드 를 죽 이려 면 rpc 서 비 스 를 사용 하거나 다른 방식 으로 통신 할 수 있 습 니 다.signal 신 호 는 더 많은 정 보 를 전달 할 수 없 기 때 문 입 니 다.
python 의 스 레 드 는 시 뮬 레이 션 이 아니 라 실제 커 널 스 레 드 입 니 다.커 널 은 pthread 방법 을 호출 하지만 Python 상층 부 는 스 레 드 를 닫 는 방법 을 제공 하지 않 았 습 니 다.이것 은 우리 가 스스로 파악 해 야 합 니 다.이벤트 나 사용자 정의 플래그 위 치 를 사용 하 는 방법 을 강력 히 추천 합 니 다.스 레 드 를 강제로 죽 이려 면 python ctypes PyThreadState SetAsyncExc 방법 으로 강제 종료 할 수 있 습 니 다.이 는 실행 중인 python 서비스 에 영향 을 주지 않 습 니 다.
이 함수 의 실현 원 리 는 비교적 간단 하 다.사실은 python 가상 컴퓨터 에서 표시 위 치 를 만 든 다음 에 가상 컴퓨터 에서 이상 을 실행 하여 스 레 드 를 취소 하고 가상 기 회 는 try cache 를 잘 만들어 준다.외부 에서 python 의 한 스 레 드 를 죽 이지 마 세 요.ctypes 를 통 해 스 레 드 id 를 찾 을 수 있 지만 직접 kill 하면 전체 프로 세 스 를 처리 할 수 있 습 니 다.
아래 코드 는 ctypes 로 스 레 드 를 죽 이 는 사례 입 니 다.사용 하 는 것 을 추천 하지 않 습 니 다.너무 거 칠 기 때 문 입 니 다.

import ctypes
 
def terminate_thread(thread):
  if not thread.isAlive():
    return
 
  exc = ctypes.py_object(SystemExit)
  res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
    ctypes.c_long(thread.ident), exc)
  if res == 0:
    raise ValueError("nonexistent thread id")
  elif res > 1:
    ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
    raise SystemError("PyThreadState_SetAsyncExc failed")



PyThreadState 소스 코드 를 간단하게 살 펴 보 겠 습 니 다.한 마디 로 스 레 드 의 이상 모드 를 촉발 합 니 다.관심 있 는 사람 은 python pystate.c 의 디자인 을 읽 고 유 튜브 의 일부 동 영상 과 함께 공유 할 수 있 습 니 다.

 
int
PyThreadState_SetAsyncExc(long id, PyObject *exc) {
  PyInterpreterState *interp = GET_INTERP_STATE();
  ...
  HEAD_LOCK();
  for (p = interp->tstate_head; p != NULL; p = p->next) {
    if (p->thread_id == id) {
               id,    ,      head_mutex。
      PyObject *old_exc = p->async_exc;
      Py_XINCREF(exc); #         
      p->async_exc = exc; #   exc  
      HEAD_UNLOCK();
      Py_XDECREF(old_exc); #      ,        
      ...
      return 1; #      
    }
  }
  HEAD_UNLOCK();
  return 0;
}
원생 poix pthread 는 ptread 를 사용 할 수 있 습 니 다.cancel(tid)은 메 인 스 레 드 에서 하위 스 레 드 를 끝 냅 니 다.그러나 Python 의 스 레 드 라 이브 러 리 는 이렇게 하 는 것 을 지원 하지 않 습 니 다.이 유 는 우리 가 하나의 스 레 드 를 강제로 끝내 서 는 안 되 기 때 문 입 니 다.그러면 많은 위험 을 가 져 올 것 입 니 다.이 스 레 드 를 스스로 끝내 야 합 니 다.그래서 Python 에서 추천 하 는 방법 은 하위 스 레 드 에서 하나의 표지 위 치 를 순환 적 으로 판단 하고 메 인 스 레 드 에서 이 표지 위 치 를 바 꾸 는 것 입 니 다.하위 스 레 드 는 표지 위치 가 바 뀌 면 자신 을 끝 냅 니 다.
이 논리 와 유사 합 니 다:

def consumer_threading():
 t1_stop= threading.Event()
 t1 = threading.Thread(target=thread1, args=(1, t1_stop))
 
 t2_stop = threading.Event()
 t2 = threading.Thread(target=thread2, args=(2, t2_stop))
 
 time.sleep(duration)
 #stop the thread2
 t2_stop.set()
 
def thread1(arg1, stop_event):
 while(not stop_event.is_set()):
   #similar to time.sleep()
   stop_event.wait(time)
   pass
 
 
def thread2(arg1, stop_event):
 while(not stop_event.is_set()):
   stop_event.wait(time)
   pass
간단 한 정 리 는 ctypes 의 pystats 로 스 레 드 를 제어 할 수 있 지만 이런 거 친 중단 스 레 드 방법 은 불합리 합 니 다.자살 모드 를 선택 하 세 요!만약 당신 의 스 레 드 가 io 차단 이 발생 하고 있다 면 사건 을 판단 하지 못 하면 어떻게 합 니까?당신 의 프로그램 은 최적화 되 어야 합 니 다.적어도 네트워크 io 층 에 서 는 주동 적 인 timeout 이 있어 야 합 니 다.계속 막 히 지 않도록 해 야 합 니 다.

좋은 웹페이지 즐겨찾기