프로필사진

Go, Vantage point

가까운 곳을 걷지 않고 서는 먼 곳을 갈 수 없다.


Github | https://github.com/overnew/

Blog | https://everenew.tistory.com/





티스토리 뷰

반응형

 

 

Python의 streamlit 라이브러리를 사용하면 간단한 구현만으로도 빠르게 웹서비스를 만들어낼 수 있다.

 

(이미지 출처: https://streamlit.io/) 스프링에 비하면 굉장히 간단하다.

 

 

 

물론 구현과 실행이 간단하더라도 웹서비스로서 동작하려면, 서버 역할을 하는 컴퓨팅 자원에서 코드가 동작해야 한다.

이를 위해 AWS EC2를 GUI로 보여주는 Cloud9 서비스에서 간단하게 웹서비스를 동작시켜 보자.

 

 

 

 

 

EC2에 streamlit 실행시키기

 

python을 설치하고 두 가지 명령어를 실행하면 바로 웹서버가 동작한다.

 

 

하지만 바로 서버 ip로 연결하면 접속이 안 될 수 있다.

 

이는 EC2의 네트워크 보안이 외부 접속을 기본적으로 차단하도록 생성되어 있기 때문이다.

따라서 인스턴스의 보안그룹에 들어가서, 인바운드 규칙을 자신의 ip 혹은 anywhereIPv4로 설정해 주자.

 

streamlit은 8501 port를 사용하므로 포트 범위는 8500-8600으로 설정해 주었다.

 

 

 

이제 streamlit hello 명령어를 통해 제공되는 externel URL에 들어가면, 기본 페이지를 확인할 수 있다.

 

 

 

기본 페이지에서 제공되는 Demo를 확인해 보면, python 데이터 처리를 통해 시각화 데이터를 보여주는데 최적화된 라이브러리임을 알 수 있다.

 

 

import streamlit as st

#타이틀
st.title("streamlit 써보기")

#헤더
st.header("header")

#텍스트
st.write("body text")

 

 

이 코드를 streamlit run main.py로 실행하면 다음과 같은 웹을 볼 수 있다.

 

 

 

 

이제 간단하게 닉네임을 설정하고 메모를 남길 수 있는 웹사이트를 만들어보자.

 

 

 

 

 

 

Streamlit으로 multiPage 만들기

 

streamlit은 정적인 페이지를 보여주는데 초점이 맞춰져 있다.

따라서 page 이동은 sidebar로 이동하도록 구현이 되어 있다.

구글링으로 찾아본 결과 버튼을 통해 이동하는 것도 streamlit에서는 구현이 힘들다고 하다.

 

page이동을 위해서는 각 page를 담당하는. py 코드에 page_config를 작성해 주어야 한다.

 

 st.set_page_config(
    page_title = "login",
    page_icon = "👋"
)

 

하위 페이지를 추가하고 싶다면 main.py와 같은 폴더 내에 pages라는 폴더를 만들어. py코드를 저장시켜야 한다.

 

 

 

먼저 닉네임을 설정하는 메인 페이지이다.

 

main.py

import streamlit as st

st.set_page_config(
    page_title = "login",
    page_icon = "👋"
)

st.title("닉네임 바꾸기")
st.sidebar.success("Select a demo above.")


name = st.text_input(label="닉네임 바꾸기", value="")

#닉네임을 세션 쿠기에 저장
st.session_state['user_name'] = name

if st.button("Confirm"):
    con = st.container()
    con.caption("Result")
    con.write(f"닉네임이  {str(name)}로 변경되었습니다.")

 

 

 

 

 

 streamlit에서 캐시 데이터를 사용하기 위해 st.session_state['key'] = 'value' 형식으로 저장하고 꺼내 쓸 수 있다.

닉네임을 받아와서 세션에 저장시키자.

 

 

다음은 메모를 작성하고 보는 memo 페이지이다.

 

memo.py

import streamlit as st

st.set_page_config(
    page_title = "memo",
)


#세션에서 닉네임 가져오기
if('user_name' not in st.session_state):
    st.session_state['user_name'] = 'unknown'
    
name = st.session_state['user_name']

st.title("닉네임: " + name)

#sideBar에 설정해 주어야 이동가능
st.sidebar.header("메모 남기기")

memo = st.text_input(label="메모 남기기", value="메모 입력")

con = st.container()
con.caption("Result")

# 기존의 메모 데이터 읽어와서 출력
file = open("memoRecord.txt", "r")
while True:
    line = file.readline()
    if not line:
        break
    con.write(line)
    
file.close()

#메모 기록하기
if st.button("메모 등록"):
    con.write(f"{name} : {str(memo)}")
    
    file = open("memoRecord.txt", "a")
    file.write(f"{name} : {str(memo)}\n")
    file.close()

 

 

 

물론 여러 명이 접속하는 페이지라면 txt 파일을 읽고 쓰는 것을 DB로 사용하는 것은 굉장히 위험하지만 일단 개인 페이지를 만드는 목적이므로 memoRecord.txt에 메모 데이터를 저장시킨다.

 

 

memoRecord.txt에 메모를 저장시키므로 닉네임을 바꾸어 들어와도

 

 

 

정상적으로 기존 데이터를 볼 수 있다.

 

 

 

 

 

 

Streamlit의 동시성 제어

 

여기서 궁금한 것은 streamlit 페이지에 접속하는 유저는 서버에서 어떻게 관리하는 걸까?

python 코드는 싱글톤이 아니라 접속하는 유저마다 실행되는 것일까?

 

유저마다 실행된다면 memo 코드에서 DB 접근에 동시성 문제가 발생할 수 있다.

 

 

이를 위해 추가적인 동시성 제어 라이브러리를 제공한다.

 

https://pypi.org/project/streamlit-sync/

 

streamlit-sync

 

pypi.org

 

 

 

Thread-safety

Each room uses its own lock (from python threading lib). Only 1 session per room can read/write the values of the room at a time. I don't know how this would impact the usability if a large amount of sessions are connected to the same room.

Each room keeps in memory the latest snapshot of values with a timestamp. A session can only update a value if it already had the latest data. This means if 2 different sessions make an action on the dashboard at the same time, 1 action will most likely be lost.

 

 

 

해당 라이브러리는 room이라는 것을 통해, 같은 room안의 session들 중에 단 하나의 session만 room의 데이터에 read/write가 가능하게 한다. 만약 동시에 두 session이 write를 한다면 한쪽은 무시될 수 있다.

 

 

모든 세션이 아래와 같이 같은 default_room에 속하도록 만드는 것이 가장 간단할 것이다.

import streamlit as st

import streamlit_sync

with streamlit_sync.sync("default_room"):
    app()

 

기본적으로 모든 widget과 value를 synce 하기 때문에 이를 벗어나고 싶다면 streamlit_sync.rooms.exit_room()

혹은 non_synce임을 명시할 수 있다.

x = st.slider("Select a value", key=streamlit_sync.get_not_synced_key("key"))

 

 

그런데 이 라이브러리는 기본적으로 UI 대상인 것 같다.

실시간의 동시성이 중요한 서비스라면,  JVM의 고질적인 속도 문제를 병렬 처리로 처리량 향상을 높이는데 목적을 둔 Java의 Spring과 같은 프레임워크가 더 좋을 듯하다.

 

 

스트림릿은 인터랙티브한 데이터 과학 응용 프로그램을 구축하기 위한 강력한 도구이지만, 몇 가지 제한 사항이 있습니다. 예를 들어 복잡한 다중 페이지 응용 프로그램을 만들기 위해 설계되지 않았으며, 기본으로 사용자 인증 또는 세션 관리를 지원하지 않습니다. (출처: https://docs.kanaries.net/ko/tutorials/Streamlit/streamlit-components)

 

 

 이야기가 산으로 가는 것 같지만,

사실 DB의 동시성 처리는 DB 수준에서 제공하는 기능을 활용해야 한다.

정말로 text로 메모 서비스를 운영하려면, text 접근에 대한 python의 동시성 코드를 사용하는 것이 맞는 것 같다.

 

 

 

 

Ec2로도 만든 웹앱을 서비스 할 수 있지만, 자체적인 cloud 서비스도 지원한다.

 

https://streamlit.io/cloud

 

Streamlit Community Cloud • Streamlit

Deploy, manage, and share your apps with the world, directly from Streamlit — all for free.

streamlit.io

 

 

반응형
댓글
반응형
인기글
Total
Today
Yesterday
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함