코드로 우주평화
메모리, csv, DB입력, 그리고 데이터 반환 본문
목표
- 메모리와 파일 시스템(csv)을 활용하여 DB에 데이터 입력
- 데이터 요청 시 벌크가 0이라면 해당 종목의 가장 최근 데이터 1개 반환
- 데이터 요청 시 벌크가 1이라면 해당 종목의 가장 최근 데이터 최대 100개 반환
문제
- 메모리에 데이터가 100개 이상이 되면 csv파일로 선입선출 방식을 통해 이동해야 함
- csv파일의 데이터는 한 번에 DB로 이동해야 함
- 유저가 요청하면 종목 코드에 맞는 데이터를 1개 또는 최대 100개까지 가져와야 함
행동
- 리스트 안에 데이터가 100개가 된다면 pop()을 이용해 선입선출로 csv로 이동하는 로직 구현
# ------------------------
# 메모리를 활용한 데이터 관리 코드
args = []
# 최근 데이터는 100개 까지 메모리에 저장한다.
# 데이터가 100개를 넘어서면 선입선출로 하나씩 csv파일로 옮겨진다.
def recent_data(arg):
args.append(arg)
if len(args) > 100:
insert_file(args.pop(0))
def insert_file(arg):
# newline='' 이 있어야 줄바꿈이 한 번만 수행됨
with open('bidasks.csv', 'a', newline='') as data:
writer = csv.writer(data)
writer.writerow(arg)
# ------------------------
- csv에 있는 데이터를 DB로 한 번에 옮기는 로직 구현
# ------------------------
# 메모리를 활용한 데이터 관리 코드
def insert_db():
# 함수내에 빈 리스트를 생성하면 함수를 호출할 때 마다 리스트를 초기화 할 수 있어 따로 clear()하지 않아도 된다
data_list = []
with open('bidasks.csv', 'r', encoding='utf-8') as data:
data = csv.reader(data)
for i in data:
data_list.append(i)
BidAskModels.insert_bulk(data_list)
# 파일 초기화를 위해 빈 파일을 덮어씌운다. 초기화하지 않으면 동일한 데이터가 계속 들어가므로.
with open('bidasks.csv', 'w') as data:
data.write("")
# ------------------------
- csv파일에서 요청 종목 코드의 최근 데이터를 1개 반환하는 로직 구현
# csv파일에서 최근 데이터를 1개 반환함
def select_file_one(code):
with open('bidasks.csv', 'r', encoding='utf-8') as data:
data = csv.reader(data)
# 컴프리핸션과 if문도 함께 써주어 코드의 효율을 높여주고
rows = [row for row in data if row[0] == code]
# 만약 데이터가 없다면 ValueError가 나오기 때문에 핸들링 해주어야 한다
if not rows:
return "No data"
# 람다를 활용해 4번째 컬럼을 기준으로 가장 큰 데이터(여기서는 최근 날짜)를 가져온다.
result_row = max(rows, key=lambda x: x[4])
result = {
"code": result_row[0],
"volume": result_row[1],
"bid": result_row[2],
"ask": result_row[3],
"timestamp": result_row[4]
}
return result
- csv파일에서 요청 종목 코드의 최근 데이터를 최대 100개 반환하는 로직 구현
# csv파일에서 최근 데이터를 최대 100개 반환함
def select_file_bulk(code):
with open('bidasks.csv', 'r', encoding='utf-8') as data:
data = csv.reader(data)
rows = [row for row in data if row[0] == code]
# 마지막 요소로부터 100번째 까지 가져옴(여기서는 최근 날짜 100개)
result_rows = rows[-100:]
# 값이 여러개 이므로 컴프리핸션을 이용해 리스트 형태로 반환!
result = [{
"code": result_row[0],
"volume": result_row[1],
"bid": result_row[2],
"ask": result_row[3],
"timestamp": result_row[4]
} for result_row in reversed(result_rows)]
return result
고민
메모리를 사용한 이유는 데이터 요청 시 csv파일의 데이터를 DB에 모두 저장하고, 이후 DB로부터 최근 데이터를 가져왔기 때문이었다. 이렇게 하면 요청과 무관한 불필요한 작업 연산이 진행되므로 효율이 좋지 않다고 판단, 메모리를 사용해 어느 정도의 최근 데이터를 미리 확보하기로 한 것이다.
하지만 메모리는 종목 코드를 따로 분류하지 않기 때문에 종목 코드에 따른 데이터는 불러오기가 어렵거나 불러와도 데이터가 빈약했다. 목적에 맞는 로직을 구현하려면 굳이 메모리를 사용하기 보다는 파일에 데이터를 모두 보관 한 뒤, DB로의 이동을 특정한 시점으로 맞추면 될 것 같았다.
결국에는 메모리 저장 코드는 빼고 실시간 데이터를 csv로 바로 저장, 그리고 별개의 요청으로 파일에 있는 데이터를 한번에 DB로 옮기도록 하였다. 이에 따라 DB에서 sql문으로 데이터를 가져오는 게 아닌, 파일 시스템(csv)에서 코드로 조건을 걸어 데이터를 가져올 수 있도록 로직을 구현했다.
앞으로
- DB언어가 아닌 파일 시스템 코드로 데이터를 가져오는 것은 내게 새로운 경험이었는데 나중에 요긴하게 써먹을 수 있을 것 같다.
- 파일에서 DB로 옮기는 로직을 장 마감 시간에 맞춰 코드가 자동으로 수행하도록 로직을 구현해보고 싶다.
레퍼런스
'Log > Today' 카테고리의 다른 글
메모리와 csv파일 데이터 합치기 (0) | 2022.01.18 |
---|---|
apscheduler를 활용한 예약 실행 성공 (0) | 2022.01.18 |
파일 시스템으로 DB 인서트 하는 중 (0) | 2022.01.14 |
threading 왜 되는 걸까? PumpMessages가 뭐길래? (0) | 2022.01.13 |
threading 으로 python병렬처리 성공 (0) | 2022.01.12 |