레이블이 thread인 게시물을 표시합니다. 모든 게시물 표시
레이블이 thread인 게시물을 표시합니다. 모든 게시물 표시

Python socket programming #4 - multiprocessing #1

Python에서 thread는 GIL(Global Interpreter Lock)을 따르게 됩니다.
간단하게 설명하면 보통은 다수의 쓰레드가 작동할 때에 아래와 같은 모델을 상상하게 됩니다.

하지만 GIL에 의해서 python은 한 Thread씩 Lock이 걸리는게 아니라 전체에 걸리게 되면서 여러개의 Thread가 Single Processor에서 동작 하는 것 처럼 동작하게 됩니다.



프로그램을 통해 살펴보면

위는 한 개의 Thread를 동작시켜 총 작업 시간을 출력한 프로그램입니다.
100000000의 숫자를 하나씩 빼면서 while문을 돌리는 간단한 프로그램입니다.
출력 결과는 아래와 같습니다.

---------------------------------------------------
Starting Thread_1
Thread_1 의 작업 시간 8
Exiting Thread_1

Exiting Main Thread
총 작업 시간 8
---------------------------------------------------

또 다른 프로그램을 살펴보면

위는 두 개의 Thread를 동작시켜 총 작업 시간을 출력한 프로그램입니다.
기본적으로 생각했을 때엔 위에서 살펴본 하나의 Thread의 작업 시간인 8초와
동일한 시간을 생각 해 볼 수 있습니다. 하지만 결과는 아래와 같습니다.

---------------------------------------------------
Starting Thread_1
Starting Thread_2
Thread_2 의 작업 시간 15
Exiting Thread_2

Thread_1 의 작업 시간 16
Exiting Thread_1

Exiting Main Thread
총 작업 시간 16
---------------------------------------------------

생각했던 것과는 다르게 하나의 Thread의 작업 시간 8초의 두 배인 16초가 출력 되는 것을 보실 수 있습니다.

위와 같은 이유로 python에서는 thread보단 multiprocessing이 권장되어집니다.

1. Multiprocessing

python에서 사용하는 multiprocessing은 fork()와 같게 생각하시면 됩니다.
하나 이상의 자식 process를 생성하여 이를 병렬구조로 처리하는 것을 지칭합니다.

import multiprocessing
위와같이 모듈을 불러와 사용 할 수 있습니다.

2. Pool

p = Pool(n)
위의 Pool(n)을 통해 미리 process를 생성 할 수 있게 됩니다.

p.map(function, values)
위의 Pool.map을 통해 각 process들이 함수를 동작 시키게 할 수 있습니다.

multiprocessing의 pool을 이용한 예제를 통해 살펴보겠습니다.

위의 예제는 pool을 통해 3개의 process를 생성하고, f(x)함수를 불러와 1초씩 함수에서 대기하게 됩니다. 결론적으로 3개의 process가 10개의 값을 연산하려면 아래와 같이 총 4초가 걸리게 됩니다.

프로세서     값        연산시간      누적 연산시간
process 1 -> 0 -------- 1초  -------- 1초
process 2 -> 1 -------- 1초  -------- 1초
process 3 -> 2 -------- 1초  -------- 1초
------------------------------------------------------
process 1 -> 3 -------- 1초  -------- 2초
process 2 -> 4 -------- 1초  -------- 2초
process 3 -> 5 -------- 1초  -------- 2초
------------------------------------------------------
process 1 -> 6 -------- 1초  -------- 3초
process 2 -> 7 -------- 1초  -------- 3초
process 3 -> 8 -------- 1초  -------- 3초
------------------------------------------------------
process 1 -> 9 -------- 1초  -------- 4초


process를 4개로 늘리거나, range를 (0,9)로 수정한다면 누적 연산시간이 3초가 걸리는 것을
확인 하실 수 있습니다.

아래는 출력 결과입니다.

값 0 에 대한 작업 Pid =  3712
값 1 에 대한 작업 Pid =  3740
값 2 에 대한 작업 Pid =  2568
값 3 에 대한 작업 Pid =  3712
값 4 에 대한 작업 Pid =  3740
값 5 에 대한 작업 Pid =  2568
값 6 에 대한 작업 Pid =  3712
값 7 에 대한 작업 Pid =  3740
값 8 에 대한 작업 Pid =  2568
값 9 에 대한 작업 Pid =  3712
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
총 작업 시간 4

Python socket programming #3 - MultiThreading (Threading module)

2. threading


두 번째로 threading 모듈은 thread 클래스를 상속받아 사용하는 모듈입니다.

클래스가 threading.Thread를 상속받아 사용하게 됩니다.

java와 마찬가지로 run 메소드를 오버라이드 하여 각 각 선언된 클래스를 통해

Class_name.start()를 작동시키면 run 메소드가 작동하게 됩니다.

위의 코드를 보면

class myThread (threading.thread):를 통해 클래스를 선언 한 뒤

생성자를 통해 thread의 name과 delay time을 인자로 받습니다.

이 후 thread1.start()를 통해 run 메소드를 작동시킵니다.

run 메소듣 내부에서는 print_count함수를 호출하여 5회 각 각 1초와 2초의 딜레이를 부여해 내용을 출력합니다.

아래는 출력 내용입니다.

Starting Thread_1
Exiting Main Thread
Starting Thread_2
Thread_1: 5
Thread_2: 5Thread_1: 4

Thread_1: 3
Thread_2: 4
Thread_1: 2
Thread_1: 1
Exiting Thread_1
Thread_2: 3
Thread_2: 2
Thread_2: 1
Exiting Thread_2

Python socket programming #2 - MultiThreading (Thread module)

파이썬에서의 멀티 쓰레딩은 두 가지의 모듈을 사용해 만들 수 있습니다.

각각의 모듈은 아래와 같습니다.


  • Thread
  • Threading


먼저 Thread는 C와 같이 함수를 이용해 Thread를 run 시키는 방식으로 MultiThreading을 구현합니다.

Threading은 흔히 자바에서 보던 방식처럼 Thread관련 클래스를 상속받아 run을 override 하여 사용합니다.

이 포스팅에선 먼저 Thread만 다루도록 하겠습니다.

1. Thread


기본적으로 Thread에서 thread를 run시키는 함수는 아래와 같습니다.

thread.start_new_thread( function, (argument))

아래 소스코드를 확인 해 보겠습니다.

위의 print_num함수에 threadName과 delay인자를 준 뒤

delay 시간만큼 텀을 두고 숫자를 1~5까지 출력하는 함수 입니다.

이 함수를 각 각 1초와 2초로 설정하여 두개의 쓰레드를 작동 시키는 프로그램입니다.

출력값은 synchronizing이 되어있지 않아 값이 겹쳐 나올 수 있게 됩니다.

마지막의 while은 Main Thread를 종료시키게 되면 생성된 2개의 쓰레드도 죽게 되므로

이를 막기위해 Main Thread에 무한루프를 걸어줍니다.

아래는 출력값 입니다.

Thread_1: 1
Thread_2: 1Thread_1: 2

Thread_1: 3
Thread_2: 2
Thread_1: 4
Thread_1: 5
Thread_2: 3
Thread_2: 4
Thread_2: 5