버퍼와 스트림
버퍼는 데이터를 메모리에 임시로 저장하는 공간을 의미한다
스트림을 버퍼에 저장된 데이터를 사용하는 방식을 의미한다 ( 지속적으로 전달하는 방식 )
버퍼
버퍼는 동영상등의 데이터가 프로그래밍으로 핸들링 될수있도록 메모리에 저장하는것이다
100mb의 동영상을 재생하는 경우 버퍼만 사용한다면 아래와 같은 일이 발생한다
100mb의 메모리를 사용할 경우 서버에 항상 100MB의 메모리를 차지한다 (메모리를 많이 사용함)
스트림
스트림은 데이터를 작은 청크(버퍼)로 나누어 보낸다 (예: 1MB씩 100번)
100mb의 동영상을 재생하는 경우 버퍼만 사용한다면 아래와 같은 일이 발생한다
100mb의 메모리를 사용할 경우 서버에 항상 1MB의 메모리를 차지한다 (메모리 절약)
스트림을 사용하는 이유
스트림 방식은 데이터를 작은 단위로 나누어 전송함으로써 메모리 사용량을 줄이는 데 있다.
반면, 버퍼 방식은 파일 전체를 메모리에 로드하여 처리한다는 점에서 큰 파일의 경우 메모리를 많이 사용하게 된다.
버퍼를 사용한 예제
@app.route('/buffer')
def buffer_example():
buffer = io.BytesIO()
with open('example.txt', 'rb') as f:
buffer.write(f.read()) # 해당 부분에서 파일을 읽어서 버퍼로 저장함 ( 반환값 : 버퍼 )
# 버퍼의 포인터를 시작 위치로 이동
buffer.seek(0)
return send_file(buffer, as_attachment=True, download_name='example.txt') # 버퍼로 저장한 파일을 클라이언트에 전송
if __name__ == '__main__':
app.run(debug=True)
스트림을 사용한 예제
def generate():
with open('example.txt', 'rb') as f: # 파일을 메모리 내의 버퍼로 읽기
while True:
chunk = f.read(1024) # 해당 부분에서 파일을 읽어서 버퍼로 저장함 ( 반환값 : 버퍼 1024바이트 )
# 청크 = 버퍼
if not chunk:
break
yield chunk
@app.route('/stream')
def stream_example():
return Response(generate(), mimetype='text/plain')
generate
함수는 파일의 내용을 작은 조각(chunk)으로 읽어서 클라이언트에게 점진적으로 전달합니다
( 즉 버퍼파일을 스트리밍방식으로 데이터를 클라이언트에 전달한다는 의미 )
버퍼링과 스트리밍의 차이
미리 여유있게 데이터를 받아놓는다 → 버퍼링
데이터를 받자마자 재생시킨다 → 스트리밍
( 둘다 버퍼라는 저장공간을 사용하며 일시적으로 저장하는 데이터의 크기에 따라 버퍼링과 스트리밍으로 나뉜다 )
( 버퍼공간을 크게해서 데이터를 미리 많이 저장해둔다 : 버퍼링 )
( 버퍼공간을 작게해서 데이터를 바로바로 쓴다 : 스트리밍 )
버퍼링
특징:
초기 일정량의 데이터를 서버에서 받아서 버퍼에 저장 후 재생을 시작합니다.
예를 들어, 100MB 파일을 받을 때 초기에 10MB를 받아 버퍼에 저장한 후 동영상을 재생합니다. 이후 1MB씩 받아가며 버퍼를 채우고 재생을 완료합니다.
초기 재생 시간이 약간 늦어질 수 있습니다.
어느 정도 데이터를 미리 받아놓기 때문에 네트워크가 일시적으로 불안해도 영상이 끊기지 않습니다.
스트리밍
특징:
데이터를 받자마자 바로 재생을 시작합니다.
예를 들어, 100MB 파일을 받을 때 서버에서 1MB를 받아 버퍼에 저장한 후 바로 동영상을 재생합니다. 이후 1MB씩 받아가며 계속 재생합니다.
초기 재생 시간이 빠릅니다.
네트워크가 불안정하면 받아놓은 데이터가 적기 때문에 영상이 끊길 수 있습니다.
한줄정리
버퍼는 공간
스트림은 방식
참조