반응형
키움 OPEN API에서는 클라이언트의 너무 빈번한 요청을 방지하기 위하여 요청간격 0.2초가 설정되어 있다. 어떤 클라이언트에서 요청 후 동일 클라이언트에서 요청하기 위해서는 0.2초 후에 가능하다. 요청간격 이전의 요청은 무시된다.
- 서버에 뭔가를 요청하는 작업을 요청작업 이라 하자.
- 전체 프로그램이 돌아가는 사이 다양한 형태의 다수의 요청작업이 시간에 관계없이 나타난다.
- 한꺼번에 많은 요청작업이 생겨도 이를 0.2초의 요청간격을 두고 순차적으로 진행해야 한다.
- 요청작업이 100개이면 모든 요청작업이 완료되기 까지 20초의 의 대기시간이 필요하다. 그 시간 동안 프로그램이 다른 작업을 할 수 없게된다.
- 프로그램은 요청작업들이 각각 요청간격을 두고 순차적으로 진행하도록 설정해두고 다른 일을 할 수 있도록 하자.
from threading import Thread, Lock
from time import localtime, strftime, time, sleep
class 요청간격:
"""
키움서버가 API 클라이언트로 부터 받는 작업요청의 시간 간격이 0.2초이다. 이를 지키려면 작업요청 전에
요청간격.체크()
를 실행해야 한다.
"""
시작시간 = 0
lock = Lock()
@staticmethod
def 체크():
"""
키움서버에 요청한 이전 시간을 확인 한 후, 필요한 만큼의 시간을 기다림.
:return:
"""
with 요청간격.lock:
지금 = time()
기다림 = (0.2 - (지금 - 요청간격.시작시간))
if 기다림 > 0: sleep(기다림)
요청간격.시작시간 = time()
def worker(num):
ts = time()
print(f'worker {num} start at {ts}')
요청간격.체크()
te = time()
print(f'worker {num} complete at {te} during {te-ts}')
for i in range(3):
worker(i)
print('모든 워커가 일을 마칠 때 까지 대기해야 함.')
sleep(1)
print('... 1초후 다른 작업을 시작합니다.')
for i in range(3):
Thread(target=worker, args=(i,)).start()
print('Thread 워커는?')
C:\ProgramData\Anaconda3-32\envs\python3.9\python.exe D:/work/projects/donkiwoom/donTest_요청간격.py
worker 0 start at 1620784693.2134843
worker 0 complete at 1620784693.2134843 during 0.0
worker 1 start at 1620784693.2134843
worker 1 complete at 1620784693.426966 during 0.21348166465759277
worker 2 start at 1620784693.426966
worker 2 complete at 1620784693.630073 during 0.20310711860656738
모든 워커가 일을 마칠 때 까지 대기해야 함.
... 1초후 다른 작업을 시작합니다.
worker 0 start at 1620784694.6335075
worker 0 complete at 1620784694.6335075 during 0.0
worker 1 start at 1620784694.6348495
worker 2 start at 1620784694.6356997
Thread 워커는?
worker 1 complete at 1620784694.834912 during 0.20006251335144043
worker 2 complete at 1620784695.0386844 during 0.402984619140625
Process finished with exit code 0
- Thread 와 Lock를 이용해야 함.
- sleep(시간)는 해당 쓰레드를 시간 만큼 쉬게한다.
- 모든 서버요청작업을 Thread로 감싸고
- Thread 안에서 서버 요청 전 요청간격.체크()를 부른다.
- 요청간격.체크()는 꼭 Thread 안에서만 해야 되는 것은 아니지만, Thread 밖에서 체크하면 모든 작업이 그 시간 만큼 대기하게 된다.
- 요청간격.체크() 는 서버 대기 시간을 확인하고 필요한 대기시간 동안 기다리게 한다.
소스 설명
- 요청간격.체크() 메쏘드는 스태틱 매쏘드로 어디서든 실행 할 수 있도록 한다.
- 각각의 worker들이 요청간격을 체크하기 위해서는 lock을 얻어야 함.
- lock은 오로지 하나의 쓰레드만이 얻을 수 있음. 다른 쓰레드에서 lock을 얻으려면 lock을 쥐고 있는 쓰레드가 그 lock을 풀어주어야 만 됨. 이를 구현하는 부분이 with 요청간격.lock: 임.
- 요청간격.시작시간은 worker 가 lock을 획득하고 요청작업을 완료한 시간이 저장됨.
- worker 가 요청간격.체크()하면 먼저 lock을 얻을 때 까지 기다려야 하고, 일단 lock을 얻으면 요청간격을 충족하는 필요한 대기 시간을 더 기다림.
- worker(num) 함수는 요청작업을 진행하는 worker. 함수의 시작과 끝의 시간을 출력하도록 함.
- 처음 3개의 워커는 쓰레드 없이 호출. 세개의 워커는 순차적으로 진행함.
- 마지막 3개의 워커는 쓰레드로 감싸서 호출. 3개의 쓰레드가 동시에 발생하여 각각 비동기적으로 진행하며 순차적으로 lock을 얻은 다음 대기시간을 기다린 후 종료된다. 그러는 사이 메인 쓰레드(프로그램)은 다른 일을 할 수 있다.
실행결과
- 처음 세개의 워커
for i in range(3):
worker(i)
-------------------
worker 0 start at 1620784693.2134843
worker 0 complete at 1620784693.2134843 during 0.0
worker 1 start at 1620784693.2134843
worker 1 complete at 1620784693.426966 during 0.21348166465759277
worker 2 start at 1620784693.426966
worker 2 complete at 1620784693.630073 during 0.20310711860656738
- worker 0은 대기시간 없이 바로 요청작업 완료
- worker 1은 worker 0 종료된 시점에서 작업 시작. 그 후 약 0.2초의 대기시간 후 작업 완료.
- worker 2은 worker 1 종료된 시점에서 작업 시작. 그 후 약 0.2초의 대기시간 후 작업 완료.
- 세 개의 워커들이 작업을 진행하는 동안 메인 쓰레드(프로그램)은 대기
- 세 개의 워커들의 작업이 완료되고 나서야 마지막 print()문이 실행됨.
- 1초의 시간을 흘려 보냄
sleep(1)
print('... 1초후 다른 작업을 시작합니다.')
- 마지막 3개의 워커(쓰레드)
for i in range(3):
Thread(target=worker, args=(i,)).start()
print('Thread 워커는?')
-------------
worker 0 start at 1620784694.6335075
worker 0 complete at 1620784694.6335075 during 0.0
worker 1 start at 1620784694.6348495
worker 2 start at 1620784694.6356997
Thread 워커는?
worker 1 complete at 1620784694.834912 during 0.20006251335144043
worker 2 complete at 1620784695.0386844 during 0.402984619140625
- 3개의 워커는 거의 동시에 작업 진입.
- worker 0 은 대기시간 없이 바로 요청작업 완료
- 3개의 워커 작업이 진입 된 후 프로그램은 마지막 print()을 실행함.
- worker 1은 worker 0이 작업 완료후 약 0.2초후 작업 완료. 결국 약 0.2초의 대기 시간이 발생함.
- worker 2는 worker 1이 작업 완료후 약 0.2초후 작업 완료. 작업 진인 이후 결국 약 0.4초의 대기시간이 발생함.
반응형
'대동단결 Python' 카테고리의 다른 글
사용자 정의 시그널 만들기 (1) | 2021.09.11 |
---|---|
사용자 정의 시그널-슬롯 (0) | 2021.05.14 |
글씨로 만들어진 이미지 만들기 (0) | 2021.01.10 |
티스토리 API에서 글 올릴 때 대표이미지 설정 (1) | 2021.01.10 |
R에서 만든 보고서를 티스토리에 자동으로 올리는 Python (0) | 2020.12.26 |
댓글