반응형

python version: 2.7


자바(Java)의 try { ... } catch (Exception e) { e.printStackTrace(); } 과 비슷한 개념으로 코드의 trace stack을 확인하는 방법:


import traceback


try:

    ....

except:

    traceback.print_exc()



오히려 try, except 없이 그냥 코드를 실행하면 프로세스는 당장 중단되더라도 call stack을 볼 수 있었는데, try, except로 감싸고 나서는 익셉션을 보는 방법이 뭔지 몰라서 그냥 print나 대충 해보다가 찾아보게 되었다. 이와 관련해서 StackOverflow에 올라온 글을 보니 내가 모르고 있어서 그렇지 traceback 관련 사용법도 sys.exc_info와 연동하는 등 다양한 것 같다 [1].


여담이지만, 자바에서는 Exception이 throw되는 지점에서 try, catch를 작성하지 않으면 컴파일 에러를 내면서 작성을 강요하는 데 비해 파이썬은 익셉션 처리를 하든지 말든그냥 두는 것이 참... 비슷한 경우로 변수의 타입을 지정하지 않고 쓰는 것과 궤를 같이 하는 것 같기도 하고, 아무튼 C/C++, Java에만 익숙해져 있다가 참 적응이 안되는 기분이다.


그래도 지금은 빨리 코딩해서 데이터부터 만들어 내야 하니까 일단 적응이 안되든지 말든지 빨리 코딩하는 걸로.



<참고자료>

[1] http://stackoverflow.com/questions/3702675/how-to-print-the-full-traceback-without-halting-the-program

반응형
블로그 이미지

Bryan_

,
반응형

부끄러운 사실이지만, 최근 들어서야 코딩할 때 파이썬(python)을 쓰기 시작했다.

말이 최근이지 불과 이틀 전이다. ㅡㅡ;;


애초에 네트워크 시뮬레이션 특성상 핵심 구현은 C/C++을 쓸 수밖에 없고, 똑같은 것을 실제 장비에서 실험을 해보려면 리눅스 디바이스 드라이버를 고쳐야 해서 결국 C를 써야 한다. 전에 연구실에서 IoT 테스트베드 구현에 깊게 참여하던 당시에는 IoT 미들웨어가 순수 Java로만 되어 있었고, 과제 연차평가를 보여줄 시연용 모바일 기기도 안드로이드여서 Java 기반이니 지금껏 Java와 C/C++만 줄기차게 써온 셈이다.


물론 스크립트 언어를 안 쓴 것은 아닌데, 그게 리눅스 쉘(shell) 스크립트와 awk였다. QualNet이나 ns-3가 만들어 내는 수많은 반복 시뮬레이션을 batch로 실행하고, 실행 후에 만들어지는 여러 개의 데이터 텍스트 파일들을 정리해서 엑셀이나 Gnuplot에 붙이기 좋게 만들 필요가 있었다. 

문제는 shell (bash)이든 awk든 스크립트 언어라서 바로바로 돌려볼 수 있기는 한데, 왠지 코드가 쉽게 써지지 않는 것은 단지 나의 기분탓이었을까? (...)


사실 bash나 awk 모두 잘(?) 쓰면 아주 강력한 스크립트 언어인 것은 분명하지만, 이상하게 빨리 익숙해지는 느낌은 잘 들지 않았다. 내가 집중적으로 실험할 때에만 폭풍처럼 몰아쳐서 스크립트를 만들다가 또 한참 안쓰고 잊어버려서 그런 것일지도? 아무튼 awk로 내가 머릿속에서 상상하는 것처럼 텍스트를 예쁜 과일 자르듯 쉽게 파싱하려면 상당한 시간의 구글링과 trial-and-error를 거쳐야만 했다.


최근에도 bash와 awk의 조합으로 ns-3 시뮬레이션을 대량으로 돌리고, 그 결과로 생성되는 텍스트 파일 중에서 몇몇 지정된 노드 번호에 대해서만 로그 데이터를 읽어들여서 파싱하는 작업을 했는데, 최근에 요구사항이 추가돼서 결과 데이터를 한번 더 가공해야 하는 상황이 되었다.

이미 만들어 놓은 awk 코드를 또 고치려니 선뜻 손이 가지 않아서, 차라리 파이썬으로 해 봐야겠다는 생각이 들어서 그냥 파이썬의 파일 입출력 예제 코드와 string 포맷팅 등의 기초적인 정보를 구글링해서 만들어 보았다.


그랬더니,


...15분 만에 결과 데이터가 내가 원하는 형태로 터미널 화면에 뙇.


Aㅏ...


기존의 awk와 shell 스크립트를 뜯어고치면 절대 완성하지 못할 시간인데...

그리고 다른 데이터에 대한 유사한 후처리 작업을 ns-3 시뮬레이션 상에서 C++ 함수로 구현해 둔 것도 있는데, 그 당시에 구현하던 때에도 30분 넘게 걸렸었는데 파이썬은 문법을 구글링하고 vi에서 생으로 코드를 짰는데도 15분이라니.

게다가 그동안 자바로 코딩했던 경험상, 똑같은 기능을 자바로 구현하면 100줄은 쉽게 넘어갈 코드가 파이썬에서 주석과 디버그용 print문 합쳐서 45라인...


...난 지금까지 뭘 한거지? ㅋㅋㅋㅋㅋ


예전에 오버레이 네트워크 상에서 돌리는 라우팅 프로토콜을 만들어야 된다고 징징거릴 때, 주변에서 파이썬으로 먼저 만들어 보는 건 어떠냐는 제안에도 파이썬을 써본 적이 전혀 없어서 익숙한 Java로 하겠다고 그랬는데...

테스트용 웹서버 구축할 때에도 Spring Boot 상에서 자바로 노동(?)을 하고 있을 때에도 옆에서 아는 형이 Django로 파이썬으로 만들면 더 빠르다고 했을 때에도 선뜻 바꿀 생각을 못했는데... @_@ (정신 가출)


다양한 프로그래밍 언어로 문자열 처리 어플리케이션 개발 시 소요되는 시간 비교(Prechelt and Garret) (출처: HACKERNOON [1])


위의 그래프가 충분히 이해가 가는 순간이다.


게다가 내가 목표로 하는 개발환경은 실행속도 따위(...) 그다지 의미가 없고, 코드만 빨리 완성되면 가상 머신 여러 개 만들어서 밤에 자는 동안 batch로 잔뜩 돌려놓기만 하면 되니까... 진작에 파이썬을 여기저기 적용해서 쓸 걸 ㅠㅠ


게다가 파이썬을 단 한번도 써본 적 없다고 괜히 겁먹은 거잖아?!

기존에 다른 프로그래밍 언어들을 장시간 다뤄본 사람 입장에서 파이썬은 배울 필요 없이 그냥 일단 쓰고 보면 되는 거였다. ㅡㅡ;;


물론 텍스트를 잘 파싱/편집/재구성하는 가장 강력한 도구로써 awk를 쓰는 것이 여전히 더 유리한 상황은 있을 것이다. 하지만 비교적 단순한 스트링 파싱은 그냥 파이썬에서 직관적인 코드를 써서 훨씬 더 빨리 만들어낼 수 있음을 이번에 경험으로 알게 되었다.

앞으로는 C++ 시뮬레이션 코드를 bash로 반복 실행을 하고, awk로 여기저기 흩어진 데이터를 한데 모으는 것까지만 하고, 그 뒤의 스트링 파싱이나 평균 계산 등은 다 파이썬으로 하면 될 것 같다.


생산성이 좋다고 주변에서 일관되게 얘기하면 그러한 줄 알고 신속하게 적용할 수 있는 사고방식의 중요성을 느낀다. ㅠㅠ

외곬수가 되지 말자...



<참고자료>

[1] Nick Humrich, "Yes, Python is Slow, and I Don’t Care," HACKERNOON,

https://hackernoon.com/yes-python-is-slow-and-i-dont-care-13763980b5a1



반응형
블로그 이미지

Bryan_

,
반응형

Java에서 사용자가 정의한 클래스를 java.util.HashMap에서 key 값으로 사용하도록 만들 때, Overriding 메쏘드 중에서 hashCode 메쏘드를 제대로 구현해야 문제없이 작동한다. 사용자 정의 클래스의 몇몇 멤버변수 값들이 다른데도 불구하고 hashCode를 제대로 구현하지 않으면 차이가 없는 것으로 판단할 수도 있기 때문이다.


C++에서는 map<const Key, T>이 비슷한 역할을 하는데, Java처럼 hashCode 함수 대신 operator < 함수를 써서 키값을 비교하는 것으로 생각된다. 

처음에는 operator = 함수만 신경써서 만들고, 실수로 operator < 함수의 내부 구현을 대충 했더니, map의 key로 서로 다른 멤버변수 값을 갖는 클래스를 대입했는데 모두 같은 value를 리턴하는 것이었다.


내 경우에는 네트워크 상의 트래픽을 표현하기 위해 Flow라는 클래스를 아래와 같이 정의했다.


class Flow {

public:

std::string srcIp;

int srcPort;

std::string dstIp;

int dstPort;

int type;

Flow();

~Flow();

};


그리고 실수로 "operator <" 함수를 아래와 같이 간단하게 만들었더니,


bool Flow::operator <(const Flow& ref) const {

return (this->srcPort + this->dstPort) < (ref.getSrcPort() + ref.getDstPort()));

}


source 또는 destination IP 주소가 서로 다른 여러 개의 flow가 모두 같은 key 값을 갖게 되는 문제가 발생했다.


그래서 std::string 형식의 IP 주소에서 숫자를 빼내서 이것들도 모두 더하는 방식으로 operator <를 구현해서 key 값이 서로 달라지도록 만들었다.


bool Flow::operator <(const Flow& ref) const {

return ((convert(this->srcIp) + this->srcPort + convert(this->dstIp) + this->dstPort) < (convert(ref.getSrcIp()) + ref.getSrcPort() + convert(ref.getDstIp()) + ref.getDstPort()));

}


이런 부분에서의 실수는 컴파일 에러에서 전혀 잡히지 않고, 가끔은 Segmentation fault 같은 에러조차 발생시키지 않고서 정상적이면서 의미상으로만 이상하게 작동하기 때문에 앞으로는 더 주의해야 할 것이다.



반응형
블로그 이미지

Bryan_

,
반응형


C/C++, Java로 코딩을 하다가 가끔 접하는 상황이 있는데, 같은 목적을 if-return의 조합과 if-else의 조합 모두로 코딩할 수 있을 때 어느 것을 선택해야 하는지에 대한 것이다.


int runSomeFunction(int a, int b){

if(condition_A){

return A;

} else {

do_something_1();

do_something_2();

}

}


--------------------------------------------------------


int runSomeFunction(int a, int b){

if(condition_A){

return A;

}


do_something_1();

do_something_2();

}


조건이 1개만 있을 때는 둘 사이에 별로 차이가 나지 않는 것 같다. 하지만 첫번째 조건 이후에 또다른 조건을 검사해야 하는 2개 이상의 nested condition이 생기면 조금 다르게 보이기 시작한다.



int runSomeFunction(int a, int b){

if(condition_A){

return A;

} else {

if(condition_B){

   return B;

} else {

   do_something_1();

   do_something_2();

}

}

}


--------------------------------------------------------


int runSomeFunction(int a, int b){

if(condition_A){

return A;

}


if(condition_B){

return B;

}


do_something_1();

do_something_2();

}


아무래도 indent가 nested condition의 수만큼 더 깊어지는(?) 문제가 생긴다. 사실 둘 사이에 성능상의 차이는 거의 없다고 보이고, 결국 코딩 스타일이나 가독성의 문제로 귀결되는 것 같다.


개인적으로는 if-return으로 처리하는 것을 선호하지만, 꼭 모든 경우에 다 if-return이 가독성이 좋다고 보기도 애매할 때가 있다. 가령, nested condition 정도가 심하지는 않으면서 각 조건마다 실행해야 하는 코드의 양이 비슷하면,



int runSomeFunction(int a, int b){

if(condition_A){

do_something_1();

do_something_2();

do_something_3();

do_something_4();

} else {

do_something_5();

do_something_6();

do_something_7();

do_something_8();

}

}


--------------------------------------------------------


int runSomeFunction(int a, int b){

if(condition_A){

do_something_1();

do_something_2();

do_something_3();

do_something_4();

return;

}


do_something_5();

do_something_6();

do_something_7();

do_something_8();

}


이런 경우에는 if-else가 서로 다른 조건에 대한 코드들의 차이를 알아보기에 더 좋은 것처럼 보인다.


if-return이 가장 효과적일 때를 생각해 본다면, 초반에 input parameter라던지 변수의 null 여부 같은 것을 확인해서 함수/메쏘드 나머지 부분의 실행 여부를 판단해야 할 때가 아닐까?


int runSomeFunction(int a, int b){

if(var_A == NULL) return;

if(var_B < 0) return;


do_something_1();

do_something_2();

do_something_3();

do_something_4();

}



결론적으로, if-else와 if-return 사이에 성능의 차이는 별로 없기 때문에 본인의 코딩 스타일과 가독성을 생각해 가면서 그때그때 상황에 맞게 정하는 수밖에 없겠다. Indentation을 많이 하는 것을 선호하지 않는다면 if-return 조합으로 코딩하는 비중이 좀더 늘어나는 정도로 생각하면 될 것 같고, 그게 꼭 정답이라기보다는 개인마다 가독성에 대한 기준도 다르니까, 맞춰서 쓰면 될 것이다.



<참고자료>

[1] http://stackoverflow.com/questions/9267643/if-return-vs-if-else-efficiency


반응형
블로그 이미지

Bryan_

,
반응형


JSP에서 자바 코드를 써서 image orientation을 먼저 알아내고,

orientation 숫자를 기준으로 회전해야 할 각도를 구해서 CSS가 회전을 수행하는 방식이다.



1. 필요한 라이브러리 다운로드 및 적용


이미지의 EXIF 정보에서 orientation을 알아내야 하기 때문에 Metadata-extractor를 쓴다.


[직접 다운로드 또는 사용법 설명]

https://github.com/drewnoakes/metadata-extractor


[Maven]

<dependency>
  <groupId>com.drewnoakes</groupId>
  <artifactId>metadata-extractor</artifactId>
  <version>2.9.1</version>
</dependency>

[Gradle]

 - dependencies에 추가

compile group: 'com.drewnoakes', name: 'metadata-extractor', version: '2.9.1'



2. 소스코드 작성


2-1. Metadata-extractor 기반의 자바 코드:


Java의 File 오브젝트를 사용해서 이미지 파일의 메타데이터 알아내는 Java 클래스를 정의한다.


import java.io.File;

import java.io.IOException;


import com.drew.imaging.ImageMetadataReader;

import com.drew.imaging.ImageProcessingException;

import com.drew.metadata.Directory;

import com.drew.metadata.Metadata;

import com.drew.metadata.MetadataException;

import com.drew.metadata.exif.ExifIFD0Directory;


public class ImageUtil {

/**

* Gets the orientation of an image (usually photo).

* Outputs:

* 6: rotate 90,

* 1: original (no change)

* 3: rotate 180,

* 8: rotate 270,

* others: original (no change)

* @param in a File object to check

* @return orientation value

* @throws IOException

*/

public static int getOrientation(File in) throws IOException {

int orientation = 1;

Metadata metadata;

Directory directory;

try {

metadata = ImageMetadataReader.readMetadata(in);

directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);

if(directory != null){

orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);

}

} catch (ImageProcessingException e) {

System.err.println("[ImgUtil] could not process image");

e.printStackTrace();

} catch (MetadataException e) {

System.err.println("[ImgUtil] could not get orientation from image");

e.printStackTrace();

}

return orientation;

}

public static int getDegreeForOrientation(int orientation){

int degree = 0;

switch(orientation){

case 6:

degree = 90; break;

case 1:

degree = 0; break;

case 3:

degree = 180; break;

case 8:

degree = 270; break;

default:

degree = 0; break;

}

return degree;

}

}



2-2. CSS 정의


실제로 이미지 회전을 수행하는 CSS 코드를 작성한다. 

html 파일에서 <head> 태그 안에 넣거나, 별도로 쓰는 css파일에 추가한다.


<style type="text/css">

.rotate90 {

   -webkit-transform: rotate(90deg);

   -moz-transform: rotate(90deg);

   -o-transform: rotate(90deg);

   -ms-transform: rotate(90deg);

   transform: rotate(90deg);

}

.rotate180 {

   -webkit-transform: rotate(180deg);

   -moz-transform: rotate(180deg);

   -o-transform: rotate(180deg);

   -ms-transform: rotate(180deg);

   transform: rotate(180deg);

}

.rotate270 {

   -webkit-transform: rotate(270deg);

   -moz-transform: rotate(270deg);

   -o-transform: rotate(270deg);

   -ms-transform: rotate(270deg);

   transform: rotate(270deg);

</style>



2-3. JSP 소스코드


먼저 2-1에서 만든 자바 클래스를 JSP에 import한다.

<%@ page import="ImageUtil이_포함된_패키지_이름.*" %>



<%

String filePath = "이미지_파일의_경로";

File f = new File(filePath);

int orientation = ImageUtil.getOrientation(f);

int degree = ImageUtil.getDegreeForOrientation(orientation);


if(degree != 0){

%>

<img src="이미지_파일의_경로" class="rotate<%=degree%>">

<%

} else {

%>

<img src="이미지_파일의_경로">

<%

}

%>




반응형
블로그 이미지

Bryan_

,