Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Python & C - Formas de Integração

Felipe cruz
November 26, 2012

Python & C - Formas de Integração

Apresentação sobre como integrar Python e C feita na Python Brasil 2012

Felipe cruz

November 26, 2012
Tweet

More Decks by Felipe cruz

Other Decks in Programming

Transcript

  1. Quem? • Trabalho há 3/4 anos com Python. • twitter:

    @felipejcruz • github: https://github.com/felipecruz
  2. Motivação • C ainda é uma linguagem muito usada e

    indiscutivelmente rápida. • Python é uma linguagem é muito usada, flexível e produtiva. • Como unir os 2 mundos?
  3. Python C Extensions - Prático • C usando a API

    C/Pyhton. • Exige compilação. • Debug mais complexo. • Compatível com PyPy através do Cpyext (não recomendado). • http://docs.python.org/3.3/extending/extending.html
  4. C - Struct de Módulo static struct PyModuleDef moduledef =

    { PyModuleDef_HEAD_INIT, "pyaio", /* m_name */ "Python POSIX aio (aio.h) bindings",/* m_doc */ -1, /* m_size */ PyaioMethods, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ };
  5. + C - Definição de funções do módulo static PyMethodDef

    PyaioMethods[] = { { "aio_read", pyaio_read, METH_VARARGS, pyaio_read_doc }, { "aio_write", pyaio_write, METH_VARARGS, pyaio_write_doc }, { NULL, NULL, 0, NULL } };
  6. + C - Inicialização do módulo PyObject * init_pyaio(void) {

    PyObject *m; PyObject *__version__; __version__ = PyUnicode_FromFormat("%s", PYAIO_VERSION); if (!__version__) { return NULL; } ...
  7. C Extensions - Observações • Permite desenvolver módulos inteiros em

    C, não somente integrar libs em C. • Tem muitos detalhes e certa complexidade. • Bom desempenho. • Pra testar é necessário compilar e instalar. • Exige mais tempo e mais cuidado.
  8. Ctypes • Permite apenas chamar código em de bibliotecas escritas

    em C. • Python puro. • API relativamente simples. • Dependendo do uso, performance pode ser um problema.
  9. Ctypes from ctypes import * from ctypes.util import find_library #

    achar uma biblioteca zmq = CDLL(find_library("zmq"), use_errno=True)
  10. Ctypes • Queremos mapear essa função C void *zmq_init (int

    io_threads); • Descrição dos métodos em Python com ctypes: zmq.zmq_init.restype = c_void_p zmq.zmq_init.argtypes = [c_int]
  11. + Ctypes zmq.zmq_socket.restype = c_int zmq.zmq_socket.argtypes = [c_void_p, c_int] #

    chamada de zmq_socket socket = zmq.zmq_socket(ctx, c_int(1))
  12. Ctypes - Performance • Para entregar uma execução pesada para

    um código eficiente em C ou se foram poucas trocas do contexto Python para o contexto C, performance não é problema. • Se exigir muitas "trocas de contexto", entre Python e C, performance pode ser um problema porque essa troca tem um custo.
  13. Ctypes - Observações • Prático para integrar com código que

    já existe. • Fácil de causar SEGFAULT no interpretador. from ctypes import c_char_p; c_char_p(1).value • Compatível com PyPy (embora não seja a melhor opção). • Python puro, testes não dependem de compilação/ instalação.
  14. Cython - Prático • Linguagem que mistura C e Python

    ou Python "anotado". • Performance equivalente a extensões nativas(C-Extensions). • Depende de compilação. • Debug baseado no GDB (em código C). • Diversos níveis de uso e complexidade. (o que é bom!)
  15. Cython - Compilação $ cython arquivo.pyx Depois, ou compila "na

    mão" ou usa setuptools/distribute para compilar e distribuir.
  16. Cython - Resumo • Boa opção para escrever extensões nativas

    poupando trabalho braçal. • É possível começar só com python puro. • Compatibilidade com PyPy em andamento.
  17. CFFI - Prático • Para escrever bindings*. • Baseado na

    API LuaJIT FFI. • Compatível com PyPy(trunk) e seu código é especializado pelo JIT. • ABI & API level.
  18. CFFI from cffi import FFI ffi = FFI() declarations =

    ''' void *zmq_init(int io_threads); void *zmq_socket(void* context, int type); ''' headers = '#include <zmq.h>' ffi.cdef(declarations) zmq = ffi.verify(headers)
  19. + CFFI zmq_ctx = zmq.zmq_init(1) zmq_socket = zmq.zmq_socket(zmq_ctx, ZMQ_PAIR) c_string

    = ffi.new('char[]', 'uma string') zmq_msg_t = ffi.new('zmq_msg_t*')
  20. CFFI - Resumo • Usar declarações em C, de um

    header file (.h) por exemplo. • API simples • Existe compilação mas é transparente. Testar é fácil. • Ótimo desempenho com PyPy (trunk).
  21. (R)Python from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.rpython.lltypesystem import rffi eci

    = ExternalCompilationInfo(includes=['zmq.h'], libraries=['zmq']) zmq_init = rffi.llexternal("zmq_init", [rffi.INT], rffi.VOIDP, compilation_info=eci) zmq_socket = rffi.llexternal("zmq_socket", [rffi.VOIDP, rffi.UINT], rffi.VOIDP, compilation_info=eci)
  22. + (R)Python def main(argv): ctx = zmq_init(1) socket = zmq_socket(ctx,

    8) zmq_connect(socket, "tcp://127.0.0.1:5555") #msg = malloc(sizeof(zmsg_t)) msg = rffi.lltype.malloc(zmsg_t.TO, flavor='raw') zmq_msg_init_size(msg, 5) #memcpy already available! rffi.c_memcpy(zmq_msg_data(msg), "aaaaa", 5) def target(*args): return main, None