bionote.net


Boost.Python을 이용한 python extension


파이썬은 단시간에 손쉽게 코드를 완성할 수 있어서, 새로운 아이디어를 구현해서 테스트해보기에 적합한 언어이다. 아이디어를 구현하는 초기에는 파이썬을 이용한 코딩이 많은 시간을 절약시켜 준다. 하지만 대용량의 데이터를 이용한 프로그램 검증이나 최적 파라미터를 찾는 등의 작업을 하기에는, 프로그램 수행속도가 느리다는 점에서 손해를 감수해야한다.

이런 문제를 해결할 수 있도록 low-level 언어인 C/C++를 이용해서 파이썬 인터페이스를 확장할 수 있다. Boost.Python은 이 확장 작업을 손쉽게 할 수 있도록 도와주는 라이브러리이다.

이후에 다시 참고하기 편하도록, 여기(http://radiohead.springnote.com/pages/712895)에서 정리한 내용을 다시 정리해본다.

  1. Boost.Python 설치
    우분투에서 다음 명령어를 이용해서 Boost.Python을 설치할 수 있다.
    $ apt-get install libboost-python-dev libboost-python1.34.1

    또는, http://www.boost.org/에서 Boost Jam과 Boost library를 다운로드 받은 후에 bjam을 이용해서 설치하는 방법이 있다.
    $ bjam --prefix=$HOME --with-python install
    --with-python 옵션을 같이 주면 Boost.Python이 설치된다. configure 명령어를 사용할 때와 마찬가지로 --prefix를 사용해서 설치위치를 지정할 수 있다.

  2. 간단한 예제 모듈
    간단한 문자열을 출력하는 예제 코드이다.
    // greet.cpp
    //
    #include <stdexcept>

    char const* greet(unsigned x) {
      static char const* const msgs[] = { "hello", "Boost.Python", "world!" };
      if (x > 2)
        throw std::range_error("greet: index out of range");
      return msgs[x];
    }

    #include <boost/python.hpp>
                       
    using namespace boost::python;
                       
    BOOST_PYTHON_MODULE(hello) {
      def("greet", greet, "return one of 3 parts of a greeting");
    }

    위의 C++ 코드를 파이썬 모듈로 작성하기 위한 setup.py를 아래와 같이 만든다.
    from distutils.core import setup, Extension

    module1 = Extension('hello',
                         include_dirs = ['/usr/include/boost'],
                         libraries = ['boost_python'],
                         library_dirs = ['/usr/lib'],
                         sources = ['greet.cpp'])

    setup (name = 'hello',
           version = '1.0',
           description = 'This is a demo package',
           ext_modules = [module1])

  3. 파이썬 인터프리터에서 예제 모듈 사용하기
    아래 명령어로 예제 코드를 빌드한다.
    python setup.py build


    빌드가 완료되면 현재 디렉토리 아래에 build/lib.linux-XXX에 hello.so가 생긴다. 이제 hello 모듈을 import해서 실행시켜 보자.
    >>> import sys
    >>> sys.path.append('build/lib.linux-XXX')
    >>> import hello
    >>> for x in range(3): print hello.greet(x)
    hello
    Boost.Python
    world!
자세한 설명과 튜토리얼은 이곳(http://www.boost.org/doc/libs/1_37_0/libs/python/doc/index.html)으로 가면 얻을 수 있다.

Boost.Python으로 alignment를 구현해보았는데 python에서 C++로 대체된 부분에 대해서 수행시간이 획기적으로 개선되었다. 특히 다른 방법들과 비교했을 때, Boost.Python은 파이썬과 비슷한 스타일로 코딩을 할 수 있다는 점이 마음에 든다.

python profiler를 이용해서 파이썬 코드의 수행시간을 분석하고, 많은 시간이 소용되는 부분에 Boost.Python을 적용하면 효과적으로 코드를 최적화할 수 있을 것이다.
2008/12/11 20:22 2008/12/11 20:22
top

 

Python으로 데몬(daemon) 프로세스 생성하기


데몬 프로세스는 백그라운드 모드로 실행되면서 사용자의 요청이 있을 때마다 적절한 작업을 수행해주는 프로세스를 말한다. 데몬이 단순한 백그라운드 프로세스와 구분되는 것이 데몬의 경우에는 부모 프로세스가 1번 init으로 세팅되어 있고 터미널을 가지고 있지 않다는 점이다. 따라서 다음의 과정을 따르면 POSIX 인터페이스를 이용해서 데몬을 작성할 수 있다 [1].
  1. fork()로 자식프로세스를 생성하고 부모 프로세스를 종료한다.
  2. 자식 프로세스에서 새로운 세션을 생성한다.
파이썬 코드로 다음과 같이 쓸 수 있다 [2].

def Daemon():
  try:
       pid = os.fork()
       if pid > 0: sys.exit(0)
  except OSError:
       print >>sys.stderr, "fork() failed"
       sys.exit(1)
  os.setsid()
  os.umask(0)
  try:
      pid = os.fork()
      if pid > 0: sys.exit(0)
  except OSError:
      print >>sys.stderr, "second fork failed"
      sys.exit(1)

  # REDIRECT STDOUT/STDERR TO OUT/ERR FILES #
  out_log = file("log/out",'a+')
  err_log = file("log/error",'a+',0)
  os.dup2(out_log.fileno(), sys.stdout.fileno())
  os.dup2(err_log.fileno(), sys.stderr.fileno())

  # DO WHAT YOU WANT HERE #

이 코드에서 첫번째 fork()는 부모 프로세스를 죽이고 새로운 세션을 생성한다. 두번째 fork()는 새로운 세션에서 데몬이 세션리더가 되는 것을 피하기 위해서 사용된다. os.setsid()에 의해서 데몬은 세션리더가 되는데, 세션리더가 터미널의 파일 기술자(file descriptor)를 열게 된다면 그 열린 터미널이 현재 세션의 터미널이 된다. 터미널을 가지면 데몬이 아니기 때문에 이런 경우를 안전하게 피하기 위해서 두번째 fork()를 사용해서 데몬 프로세스가 세션리더가 되는 것을 방지한다 [2].

References
[1] C로 간단한 데몬(daemon)제작하기, http://data.oss.or.kr/sw/view.html?sort=&num=649&page=1
[2] Fork a daemon process on Unix, http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012
2006/07/18 09:54 2006/07/18 09:54
top

 

큐잉(queueing) 기능의 구현


단백질의 구조를 자동으로 예측해주는 서버를 구축해서 시험 가동하던 중 한가지 문제가 생겼다. 한꺼번에 다수의 쿼리가 수행될 경우에 전체 시스템이 느려지는 현상이 발생한다. 따라서 큐잉 기능을 추가할 필요가 생겼다.

요구사항은 다음과 같다.
  1. 다수의 작업이 입력되더라도 가장 먼저 입력된 하나의 작업만을 프로세서에서 처리되도록 한다.
  2. 현재 작업큐의 상태를 모니터링할 수 있어야 한다. 이때 보여주는 정보는 작업명, 인덱스, 입력시간을 반드시 포함한다.
  3. 작업이 큐에 대기하는 시간을 최소한이 되도록 효율적이어야 한다.

조사해 본 바로는 UNIX의 named pipe를 이용하면 큐잉 기능을 구현하는 것이 가장 간편해 보였다. 실제로 병철 선배가 같은 방식으로 큐잉을 구현해봤는데 간단하고 지금도 정상적으로 작동하고 있다고 한다. 파이썬에서도 mkfifo() 함수를 제공하고 있어서 일반파일처럼 read(), write() 함수로 다룰 수 있다 [조성준, [예제] FiFO(Named Pipe), http://www.openphp.com].

사용자로부터 입력을 받으면 1) 웹프로그램은 작업큐에 작업을 입력한다. 각각의 정보를 '\0'로 구분해서 하나의 작업이 하나의 라인에 저장되도록 한다. 2) 서버 프로그램은 데몬처럼 돌면서 FIFO에 read()를 수행하고 read()가 성공하면 실제 구조 예측 프로그램에 의해서 작업이 수행되도록 한다. 3) 구조 예측 작업이 끝나면 다시 read()를 시도하는 일부터 루프를 돈다.

2006/07/17 00:28 2006/07/17 00:28
top