파이썬 스레딩: 소개
게시 됨: 2022-10-25이 자습서에서는 Python의 내장 스레딩 모듈을 사용하여 Python의 다중 스레딩 기능을 탐색하는 방법을 배웁니다.
프로세스와 스레드의 기본부터 시작하여 동시성과 병렬성의 개념을 이해하면서 Python에서 멀티스레딩이 작동하는 방식을 배우게 됩니다. 그런 다음 내장 threading
모듈을 사용하여 Python에서 하나 이상의 스레드를 시작하고 실행하는 방법을 배웁니다.
시작하자.
프로세스 대 스레드: 차이점은 무엇입니까?
프로세스란?
프로세스 는 실행해야 하는 프로그램의 모든 인스턴스입니다.
Python 스크립트 또는 Chrome과 같은 웹 브라우저에서 화상 회의 애플리케이션에 이르기까지 무엇이든 될 수 있습니다. 컴퓨터에서 작업 관리자 를 시작하고 성능 –> CPU 로 이동하면 현재 CPU 코어에서 실행 중인 프로세스와 스레드를 볼 수 있습니다.

프로세스 및 스레드 이해
내부적으로 프로세스에는 해당 프로세스에 해당하는 코드와 데이터를 저장하는 전용 메모리가 있습니다.
프로세스는 하나 이상의 스레드 로 구성됩니다. 스레드는 운영 체제가 실행할 수 있는 가장 작은 명령 시퀀스이며 실행 흐름을 나타냅니다.
각 스레드에는 자체 스택과 레지스터가 있지만 전용 메모리는 없습니다 . 프로세스와 연결된 모든 스레드는 데이터에 액세스할 수 있습니다. 따라서 데이터와 메모리는 프로세스의 모든 스레드에서 공유됩니다.

N개의 코어가 있는 CPU에서 N개의 프로세스는 동일한 시간에 병렬로 실행할 수 있습니다. 그러나 동일한 프로세스의 두 스레드는 병렬로 실행할 수 없지만 동시에 실행할 수 있습니다. 다음 섹션에서 동시성 대 병렬성의 개념을 다룰 것입니다.
지금까지 배운 내용을 바탕으로 프로세스와 스레드의 차이점을 요약해 보겠습니다.
특징 | 프로세스 | 실 |
메모리 | 전용 메모리 | 공유 메모리 |
실행 모드 | 병렬, 동시 | 병발 사정; 그러나 평행하지 않다 |
에 의해 처리되는 실행 | 운영 체제 | CPython 인터프리터 |
파이썬의 멀티스레딩
Python에서 GIL(Global Interpreter Lock)은 한 스레드만 잠금을 획득하고 특정 시점에서 실행할 수 있도록 합니다. 모든 스레드가 실행하려면 이 잠금을 획득해야 합니다. 이렇게 하면 특정 시점에서 단일 스레드만 실행될 수 있고 동시 멀티스레딩이 방지됩니다.
예를 들어, 동일한 프로세스의 두 스레드 t1
및 t2
를 고려하십시오. 스레드는 t1
이 특정 값 k
를 읽을 때 동일한 데이터를 공유하기 때문에 t2
는 동일한 값 k
를 수정할 수 있습니다. 이는 교착 상태 및 바람직하지 않은 결과를 초래할 수 있습니다. 그러나 스레드 중 하나만 잠금을 획득하고 모든 인스턴스에서 실행할 수 있습니다. 따라서 GIL은 스레드 안전성 도 보장합니다.
그렇다면 파이썬에서 멀티스레딩 기능을 어떻게 달성할 수 있을까요? 이를 이해하기 위해 동시성과 병렬성의 개념에 대해 논의해 보겠습니다.
동시성 대 병렬성: 개요
하나 이상의 코어가 있는 CPU를 고려하십시오. 아래 그림에서 CPU에는 4개의 코어가 있습니다. 이는 주어진 순간에 4개의 다른 작업을 병렬로 실행할 수 있음을 의미합니다.
4개의 프로세스가 있는 경우 각 프로세스는 4개의 코어 각각에서 독립적으로 동시에 실행할 수 있습니다. 각 프로세스에 두 개의 스레드가 있다고 가정해 보겠습니다.

스레딩이 작동하는 방식을 이해하기 위해 멀티코어에서 단일 코어 프로세서 아키텍처로 전환해 보겠습니다. 언급했듯이 특정 실행 인스턴스에서 단일 스레드만 활성화될 수 있습니다. 그러나 프로세서 코어는 스레드 간에 전환할 수 있습니다.

예를 들어, I/O 바운드 스레드는 종종 사용자 입력 읽기, 데이터베이스 읽기 및 파일 작업과 같은 I/O 작업을 기다립니다. 이 대기 시간 동안 다른 스레드가 실행될 수 있도록 잠금을 해제 할 수 있습니다. 대기 시간은 n
초 동안 잠자기와 같은 간단한 작업일 수도 있습니다.
요약: 대기 작업 중에 스레드는 잠금을 해제하여 프로세서 코어가 다른 스레드로 전환할 수 있도록 합니다. 대기 기간이 완료된 후 이전 스레드가 실행을 재개합니다. 프로세서 코어가 스레드 간에 동시에 전환하는 이 프로세스는 멀티스레딩을 용이하게 합니다.
애플리케이션에서 프로세스 수준 병렬 처리를 구현하려면 대신 다중 처리를 사용하는 것이 좋습니다.
Python 스레딩 모듈: 첫 번째 단계
Python은 Python 스크립트로 가져올 수 있는 threading
모듈과 함께 제공됩니다.
import threading
파이썬에서 스레드 객체를 생성하기 위해 Thread
생성자를 사용할 수 있습니다: threading.Thread(...)
. 이것은 대부분의 스레딩 구현에 충분한 일반 구문입니다.
threading.Thread(target=...,args=...)
여기,
-
target
은 Python 호출 가능을 나타내는 키워드 인수입니다. -
args
는 대상이 받는 인수의 튜플입니다.
이 자습서의 코드 예제를 실행하려면 Python 3.x가 필요합니다. 코드를 다운로드하고 따라해보세요.
Python에서 스레드를 정의하고 실행하는 방법
대상 함수를 실행하는 스레드를 정의해 보겠습니다.
대상 함수는 some_func
입니다.
import threading import time def some_func(): print("Running some_func...") time.sleep(2) print("Finished running some_func.") thread1 = threading.Thread(target=some_func) thread1.start() print(threading.active_count())
위의 코드 조각이 하는 일을 구문 분석해 보겠습니다.
-
threading
및time
모듈을 가져옵니다. - 함수
some_func
에는 설명이 포함된print()
문이 있으며 2초 동안 휴면 작업을 포함합니다.time.sleep(n)
은 함수를n
초 동안 휴면 상태로 만듭니다. - 다음으로 target이
some_func
인 스레드thread_1
을 정의합니다.threading.Thread(target=...)
는 스레드 객체를 생성합니다. - 참고 : 함수 호출이 아닌 함수 이름을 지정하십시오.
some_func()
가 아닌some_func
를 사용하십시오. - 스레드 개체를 생성하면 스레드가 시작 되지 않습니다 . 스레드 개체에서
start()
메서드를 호출하면 됩니다. - 활성 스레드 수를 얻으려면
active_count()
함수를 사용합니다.
Python 스크립트는 메인 스레드에서 실행 중이며, 출력에서 볼 수 있듯이 활성 스레드 수가 2가 되도록 some_func
함수를 실행하기 위해 다른 스레드( thread1
)를 생성합니다.

# Output Running some_func... 2 Finished running some_func.
출력을 자세히 살펴보면 thread1
시작 시 첫 번째 print 문이 실행되는 것을 알 수 있습니다. 그러나 절전 작업 동안 프로세서는 메인 스레드로 전환하고 스레드 1이 실행을 thread1
때까지 기다리지 않고 활성 스레드 수를 인쇄합니다.

스레드가 실행을 마칠 때까지 기다리기
thread1
이 실행을 끝내도록 하려면 스레드를 시작한 후 join()
메서드를 호출하면 됩니다. 그렇게 하면 메인 스레드로 전환하지 않고 thread1
이 실행을 마칠 때까지 기다립니다.
import threading import time def some_func(): print("Running some_func...") time.sleep(2) print("Finished running some_func.") thread1 = threading.Thread(target=some_func) thread1.start() thread1.join() print(threading.active_count())
이제 활성 스레드 수를 인쇄하기 전에 thread1
의 실행이 완료되었습니다. 따라서 메인 스레드만 실행 중이며, 이는 활성 스레드 수가 1개임을 의미합니다.
# Output Running some_func... Finished running some_func. 1
Python에서 여러 스레드를 실행하는 방법
다음으로 두 개의 다른 기능을 실행하는 두 개의 스레드를 만들어 보겠습니다.
여기서 count_down
은 숫자를 인수로 받아 그 숫자에서 0까지 카운트다운하는 함수입니다.
def count_down(n): for i in range(n,-1,-1): print(i)
count_up
, 0에서 주어진 숫자까지 세는 또 다른 Python 함수를 정의합니다.
def count_up(n): for i in range(n+1): print(i)
range()
함수를range(start, stop, step)
구문과 함께 사용할 때 종점stop
은 기본적으로 제외됩니다.– 특정 숫자에서 0으로 카운트다운하려면 음수
step
값 -1을 사용하고stop
값을 -1로 설정하여 0이 포함되도록 할 수 있습니다.– 마찬가지로
n
까지 카운트하려면stop
값을n + 1
로 설정해야 합니다.start
와step
의 기본값은 각각 0과 1이므로range(n + 1)
을 사용하여 0에서 n까지의 시퀀스를 얻을 수 있습니다.
다음으로, count_down
및 count_up
함수를 각각 실행하기 위해 두 개의 스레드( thread1
및 thread2
)를 정의합니다. 두 함수 모두에 대해 print
문과 sleep
작업을 추가합니다.
스레드 객체를 생성할 때 대상 함수에 대한 인수는 args
매개변수에 대한 튜플로 지정되어야 합니다. 두 함수( count_down
및 count_up
) 모두 하나의 인수를 취하기 때문입니다. 값 뒤에 명시적으로 쉼표를 삽입해야 합니다. 이렇게 하면 후속 요소가 None
으로 유추되기 때문에 인수가 여전히 튜플로 전달됩니다.
import threading import time def count_down(n): for i in range(n,-1,-1): print("Running thread1....") print(i) time.sleep(1) def count_up(n): for i in range(n+1): print("Running thread2...") print(i) time.sleep(1) thread1 = threading.Thread(target=count_down,args=(10,)) thread2 = threading.Thread(target=count_up,args=(5,)) thread1.start() thread2.start()
출력에서:
-
thread2
함수는count_up
에서 실행되며 0에서 시작하여 최대 5까지 계산합니다. -
count_down
함수는thread1
에서 실행되며 10에서 0까지 카운트다운합니다.
# Output Running thread1.... 10 Running thread2... 0 Running thread1.... 9 Running thread2... 1 Running thread1.... 8 Running thread2... 2 Running thread1.... 7 Running thread2... 3 Running thread1.... 6 Running thread2... 4 Running thread1.... 5 Running thread2... 5 Running thread1.... 4 Running thread1.... 3 Running thread1.... 2 Running thread1.... 1 Running thread1.... 0
thread1
과 스레드 2는 모두 대기 작업(수면)을 포함하므로 thread2
실행되는 것을 볼 수 있습니다. count_up
함수가 5까지 카운트를 마치면 thread2
는 더 이상 활성화되지 않습니다. 따라서 우리는 thread1
에만 해당하는 출력을 얻습니다.
합산
이 자습서에서는 Python의 내장 스레딩 모듈을 사용하여 멀티스레딩을 구현하는 방법을 배웠습니다. 주요 내용을 요약하면 다음과 같습니다.
- Thread 생성자는 스레드 개체를 만드는 데 사용할 수 있습니다. threading.Thread(target=<callable>,args=(<tuple of args>)) 를 사용하면 args 에 지정된 인수로 대상 호출 가능을 실행하는 스레드가 생성됩니다.
- Python 프로그램은 기본 스레드에서 실행되므로 생성한 스레드 개체는 추가 스레드입니다. active_count() 함수를 호출하면 모든 인스턴스에서 활성 스레드 수를 반환합니다.
- 스레드 개체에서 start() 메서드를 사용하여 스레드를 시작하고 join() 메서드를 사용하여 실행이 완료될 때까지 기다릴 수 있습니다.
대기 시간을 조정하고 다른 I/O 작업을 시도하는 등의 방법으로 추가 예제를 코딩할 수 있습니다. 향후 Python 프로젝트에서 멀티스레딩을 구현해야 합니다. 즐거운 코딩!