python bulk write / text write to file / 파일 write / file io 빠르게 /
python io 성능관련 글
Text I/O
text stream 을 만드는 간단한 방법은 open() 함수를 사용하는 것
f = open("mytext", "r")
in-memory text stream 들은 StringIO object들을 이용하면 된다.
f = io.StringIO("initial text")
Binary I/O
Binary I/O 를 buffered I/O 라고 도 부른다.
f = open("myfile.jpg", "rb")
in-memory binary stream
f = io.BytesIO(b"some initial binary data: \x00\x01")
성능
ref.1 에 좋은 글이 있어서 일부 번역을 해 놓는다.
다음 4가지에 IO에 대한 성능 이야기다.
- Binary I/O
- Text I/O
- Multi-threading
- Reentrancy
Binary I/O
buffered I/O 는 사용자가 1 byte를 요청해도, 많은 양의 데이터만 읽고 기록함으로써 os의 unbuffered I/O 루틴들을 불러서 수행할 때 생기는 비효율을 숨긴다. 이득(benefit)은 OS와 ’수행하는 I/O 종류’에 달려있다. 예를 들면, linux 같은 최신 OS들 에서는 unbuffered disk I/O 가 buffered I/O 보다 더 빠를 수 있다. 그러나 최소한(bottom line), buffered I/O 는 지원장치(backing device)나 플랫폼에 상관없이 예측가능한 성능을 제공한다는 것이다. 그런이유로 ’buffered I/O 를 사용하는 것’은 binary data 에 대해서 unbuffered I/O를 사용하는 것보다는 거의 언제나 선호된다.
Text I/O
file같은 binary storage(저장)에 대한 Text I/O 는 같은 저장에 대한 binary I/O 에 비해 현저히 늦다. 왜냐하면, Text I/O 는 unicode 와 binary data 사이에 문자 코덱을 이용한 변환이 필요하기 때문이다. 이것은 큰 log file들 같은 거대한 양의 text data에 대한 처리에서 눈에띄게 느릴 것이다. 또한 TextIOWrapper.tell()
과 TextIOWrapper.seek()
의 경우는 사용되는 재구성 방법(reconstruction algorithm)때문에 둘다 꽤나 느리다.
그러나 StringIO는 native in-memory unicode container면서 BytesIO 와 유사한 속도를 보여줄 것이다.
Multi-threading
FileIO object들은 그들이 wrap 한 Unix 에서 read(2) 같은 os system call 들 thread-safe 하는 정도로 thread-safe 하다. (me: 그들이 wrap 한 함수만큼 thread-safe 하다는 말인듯.)
Binary buffered object들(BufferedReader,BufferedWriter,BufferedRandom,BufferedRWPair)은 그들의 내부 구조들을 lock 을 이용해서 보호한다. 그렇기 때문에 여러 thread 에서 동시에 그들을 호출하는것이 안전하다.
TextIOWrapper object들은 thread-safe 하지 않다.
Reentrancy
Binary buffered object들(BufferedReader,BufferedWriter,BufferedRandom,BufferedRWPair)은 reentrant 하지 않다. 반면에 reentrant call들은 일반적인 상황에서 일어나지 않지만, 그들은 signal handler 에서 I/O 를 하고 것으로부터 일어날 수 있다.
만약에 thread 가 이미 접근했던 buffered object 에 재진입(re-enter) 하려고 노력한다면, RuntimeError 가 발생된다. 하지만 이것은 다른 thread 가 buffered object 로 들어가는 것을 막지 않는다.
위의 이야기는 잠재적으로 text file들로 확장된다. open() 함수가 TextIOWrapper 내에서 buffered object 를 wrap 할 것이기 때문이다.
정리
명확하지 않지만, 지금 뇌피셜로 어느정도 flow 를 정리해보면, 아래와 같지 않을까 싶다. 일단 아래 사항은 그저 뇌피셜로 만든것이라 너무 믿지말자.
write('fds') ----> memory (os buffer) ----> device buffer ---> device
write('fds') ----> memory (ByteIO buffer) ----> memory (os buffer) ----> device buffer ---> device
- text i/o 작업할때 좀 더 빠른 성능은 StringIO 를 이용하자.
- 대체로 buffered I/O 가 빠르다.
- binary buffered object 들은 thread-safe 하다
StringIO 내용을 file 로 wrtie 하기
shutil 를 이용해서 복사한다.
with open('file.xml', 'w') as fd:
buf.seek(0)
shutil.copyfileobj(buf, fd)
댓글 없음:
댓글 쓰기