
seen from Belgium
seen from Türkiye

seen from United States
seen from Belgium
seen from Germany
seen from United States
seen from Malaysia

seen from Switzerland
seen from Netherlands

seen from Switzerland
seen from United States
seen from United States
seen from United States
seen from Malaysia

seen from Malaysia
seen from Türkiye
seen from United States
seen from Belarus
seen from South Korea
seen from United States
File, StringIO, cStringIO in Python
며칠 전에 인턴에게 외부의 DB에서 대량의 데이타를 가지고 와서 내부 DB에 저장하는 코드의 작성을 맡겼다. 오늘 결과 코드를 리뷰하며 다량의 INSERT를 사용하는 대신에 PostgreSQL의 COPY FROM 기능을 사용하여 작성을 해놓은 것을 확인하였다. 나름 속도에 대해서 생각해가면서 작업을 한 것이 좋았다. 그러나...아앗...이런...PostgreSQL의 Copy는 'csv', 'text', 'binary'포맷의 파일을 입력으로 받아서 이를 벌크 생성하는데...이를 위해서 중간 파일을 작성해야하고 이를 다른 중간파일로 다시 처리하는 코드가 들어가 있었다. 파이썬 [csv](http://docs.python.org/2/library/csv.html) 모듈이 Null값을 제대로 처리 안 하는 것 때문에 이를 처리 하기 위한 2번째 중간파일을 만들고 이를 다시 읽어서 파이썬의 postgresql db api로 넘기는 것이 아닌가... :-( 대량의 insert를 반복하는 것보다 성능이 더 떨어질 것 같은 느낌이 들었다. 해결책을 찾아서 virtual file이나 memory file 들을 검색해본 결과 StringIO와 cStringIO라는 모듈을 찾을 수 있었다. 이거들은 파이썬 기본 라이브러리에 있는 모듈로 file object와 동일한 인터페이스를 제공하는 memory object이다. 바로 2가지 작업을 하였다. - 2번째 중간파일을 만드는 원인인 Null 처리 부분을 별도의 파일을 만들지 않고 1번째 중간파일을 만들때 바로 적용하도록 수정하였다. - 중간 파일을 StringIO로 변경하여 모든 작업이 메모리에서 이루어지도록 하였다. 집에 와서 간단히 테스트를 해보았는데, 250MB 정도의 데이터를 중간파일에 넣어 작업을 하는 경우에 실제 디스크의 파일을 쓰지 않고 StringIO와 cStringIO를 쓰니 다음과 같은 성능 향상을 얻을 수 있었다. :-) 실 코드에서는 1번 파일을 쓰고 1번 파일을 읽어 2번 파일을 쓰고 2번 파일을 다시 읽는 것을 없앤 것이니 성능 향상이 몇 배 더 클 것이다. 그러고 보니 테스트를 돌린 노트북은 SSD를 쓰니 이것도 고려해야될 듯... 여튼 메모리는 디스크보다 아주 많이 빠르다. :-) - Disk : 65.83 - StringIO : 1.34 - cStringiO : 1.03 cStringIO가 StringIO보다 성능이 약간 더 좋은데, StringIO가 순수 파이썬 코드라면 cStringIO는 네이티브 바이너리 라이브러리를 사용한다. 성능이 좋은 대신 약간의 제약이 있는데... StringIO가 unicode string이랑 multibyte string을 모두 처리할 수 있는 것에 비해 cStringIO는 unicode string을 처리하지 못 한다. 테스트를 하는 과정에서 약간의 삽질이 있었는데, 메모리를 쓰는 경우와 디스크를 쓰는 경우의 시간 차이가 나지 않는 것이였다. 파이썬을 리눅스에서 실행할때에는 clock()에서 해당 프로세스의 실행시간만을 반환한다. 즉, 파일IO등으로 걸린 시간은 포함되지 않는다. 그러니 이런 비교를 할때 시간 측정에는 clock()을 쓰면 안 된다. 반면 윈도에서는 clock()은 파일IO등의 시간도 포함되어 계산된다. 위 비교표는 테스트 코드를 윈도에서 실행한 결과이다. 오늘의 결론. 1. 해당 툴의 기능을 최대한 이용하자. insert 대신 copy? 2. 진정한 병목을 찾아서 최적화를 하자. 디스크는 메모리보다 매우 느리니 메모리가 충분하다면 메모리에서 처리하자. 3. 신뢰할 수 있는 라이브러리의 동작이 수상할 때에는 문서를 잘 읽어보라. 참고 링크 - [PostgreSQL COPY](http://www.postgresql.org/docs/9.1/static/sql-copy.html) - [Python StringIO, cStringIO](http://docs.python.org/2.7/library/stringio.html)
StringIO example
In this short article I will present a scenario where I found StringIO class useful.
According to ruby reference manual
Another way to obtain an IO object is to use the stringio library to read from or write to a string [...]The StringIO class is not a subclass of IO, but it defines many of the same methods as IO does, and duck typing usually allows us to use a StringIO object in place of an IO object.
Suppose you are writing some sort of file cruncher (file parser for example). When it comes to testing your functionality first what strokes your mind can be create a folder test/tmp/ with test files - and run tests on them. However this option becomes tedious when you will have to deal with 100 file 5-10 lines each. Here StringIO comes into play. You can use StringIO object instead of File object. StringIO - behaves like a String and like File object in same time. There is no need to open file from somewhere to read text content - just push that content to StringIO object and then feed StringIO object instead of File.
An example is worth one thousand of words:
Conclusion
During testing it can be more convenient to use StringIO object instead of File object.