1. 국내주식/1-1. 국내주식 연구일지

(파이썬) 주식 multiprocessing.Process 적용하여 다중 병렬 처리하기

봄이오네 2022. 9. 14. 02:11
반응형

1. 들어가며

1) 파이썬으로 주식코드를 만들고 3가지 정보를 받으려고,
파이참에서 실행(shift + f10)했는데, 1가지 정보만 받아왔다.
2) 이유는, 파이썬의 GIL(Global Interpreter Lock) 때문이며,
파이썬 인터프리터는 한 스레드에서 하나의 코드를 실행시킬 수 있도록 해주기 때문이다.

- 예를 들어, 즉, a함수가 1분마다 실행되고 있다면, 이 경우 b,c 함수는 미실행된다
* a함수는 1분마다 1분봉 받기,
b는 5초마다 현재가 받기, c는 5초마다 매수가 받기 함수


2. 접근 방법

ㅇ 파이썬의 GIL을 우회하는 방법(병렬 처리)으로 검색을 해보니,
라이브러리 중 asyncio, multithreading, multiprocessing 등 3가지를 알아보았다.
- asyncio : 함수 앞에 일일히 asyncio를 붙이고, 전달변수 앞에 await를 붙이는 등
코드 변경이 심한거 같음 → 미채택
- multithreading : 리스트 threads를 만들어 주어야 하고, target을 넣어주는 등 불편하고,
time.sleep(1)를 넣어주는 등 시간 소요 → 미채택
- multiprocessing : 코드의 변경이 심하지 않고, 직관적으로 1줄씩만 넣어주면 됨 → 채택


3. 기타 사항

1) 인터넷 검색으로는 다중처리 라이브러리에 대해 소요되는 시간에 중점을 두고 설명하지만,
이 글에서는 "소요시간"보다는 다중처리 실행할 수 있는지에 대해 설명 예정
2) 파이썬 3.9.12 기준으로 작성하였으며, 아래 출처에 있는 내용을 코드로 구현하여 실행
* 출처 : https://docs.python.org/ko/3/library/multiprocessing.html


4. 단일 프로세스가 적용

1) 단일 프로세스 코드 : if __name__ == '___main__ ':
아래에 함수 2줄(AAA.f(), AAA.g())이 단일 프로세스를 활용하는 코드이다.

# from multiprocessing import Process
import os
# import threading

class AAA():
    def f():
        print(1 + 2)
        print(os.getpid())
        # threading.Timer(3, AAA.f).start()

    def g():
        print(3 + 4)
        print(os.getpid(   ))
        # threading.Timer(6, AAA.g).start()

if __name__ == '__main__':
    AAA.f()
    AAA.g()

2) 단일 프로세스 적용 화면 → 프로세스 주소가 "10712"로 고정


5. 코드 작성 과정 (다중 병렬 처리 적용)

1) 라이브러리 2개를 불러온다.
- 다중처리를 위한 multiprocessing와 Process ID를 구하기 위해 os모듈을 활용한다.
(둘다 python 내장함수)

from multiprocessing import Process
import os
# import threading

2) 주식시스템의 구현을 위해 1개의 클래스 안에 2개의 함수를 구현한다.
* threading.Timer(3, AAA.f).start() → 3초마다 f함수를 실행

class AAA():
    def f():
        print(1 + 2)
        print(os.getpid())
        # threading.Timer(3, AAA.f).start()

    def g():
        print(3 + 4)
        print(os.getpid(   ))
        # threading.Timer(6, AAA.g).start()


3) 실행 파일에는 Process를 설정하고, 시작(start)해 주고,
프로세스가 종료될때까지 block해주는 join함수를 넣어준다.
* 필자는 1분마다 1분봉 받는 함수를 장중 내내 실행시키기 위해,
join은 프로세스가 작업을 완료하고 종료될때까지 기다릴 때 사용하는 명령어이다.

if __name__ == '__main__':
    p = Process(target=AAA.f,)
    q = Process(target=AAA.g,)
    p.start()
    # p.join()
    q.start()
    # q.join()

6. 전체 코드

ㅇ 3초~6초마다 f함수와 g함수를 실행하고 싶으면, 아래의 3가지 주석 해제
* 3번줄(import)및 9번줄(timer), 14번줄(timer) 주석 해제

from multiprocessing import Process
import os
# import threading

class AAA():
    def f():
        print(1 + 2)
        print(os.getpid())
        # threading.Timer(3, AAA.f).start()

    def g():
        print(3 + 4)
        print(os.getpid(   ))
        # threading.Timer(6, AAA.g).start()

if __name__ == '__main__':
    p = Process(target=AAA.f,)
    q = Process(target=AAA.g,)
    p.start()
    # p.join()
    q.start()
    # q.join()

7. 코드 결과

ㅇ 2개 프로세스 주소 : f함수 실행 결과 4532(프로세스 주소),
g함수 실행결과 3196(프로세스 주소)가 출력됨
→ 즉, 2개 프로세스를 활용한다.


8. 마무리

ㅇ 간단한 코드는 다중처리(다른 프로세스 주소)가 실행되는 모습을 보았다.
동 내용을 주식 시스템의 소스코드에 적용하여 다중처리가 된다면,
좀 더 빠른 연산속도와 파이썬의 GIL을 일부나마 우회할 수 있지 않을까 생각된다.

반응형