2011-04-30 5 views
7

내 사진 블로그에 게시하는 데 사용하는 GTK (GObject) 인터페이스가있는 스크립트가 있습니다.python 및 gobject의 이미지로드 성능 문제가 발생했습니다.

이미지를 백그라운드 스레드에로드하여 응답 속도를 향상 시키려고합니다.

백그라운드 스레드에서 GdkPixbuf 개체를 채우려 고 시도한 행운이 없었습니다. 모든 시도는 단색이었습니다.

그래서 나는 백그라운드 스레드에서 파일을 읽고 GdkPixbuf를 필요할 때 밀어 넣을 것이라고 생각했습니다. 이 접근법은 놀랍고 다소 우울한 성과 결과를 낳았습니다. 이는 제가 크게 잘못된 것을하고 있는지 궁금하게 생각합니다.

카메라에서 가볍게 압축 된 jpeg로 재생할 때 주변에서 약 3.8MB가되는 경향이 있습니다.

여기에 원래의 차단 이미지로드의 :

pb = GdkPixbuf.Pixbuf.new_from_file(image_file) 

이 평균 거대한, 그러나 당신이 다스 이미지를 가볍게하려는 경우 오히려 지루하지 약 550ms가.

data = bytearray(open(self.image_file).read()) 

이 평균의 15ms의 우리가 15ms의에서 파일을 읽을 수 있는지 즉 지출되고 다른 535ms 무엇인지, 좀 걱정도 정말 좋은,하지만입니다 :

그럼 내가 여기 읽을 파일, 그것은을 분할 에?

덧붙여서 PixBufLoader가 그렇지 않으면 데이터를 받아 들일 수 없기 때문에 bytearray 호출이 존재합니다.

그리고 다음 Pixbuf로드

:은 Gtk는 모든 것을 할시키는 것보다 거의 3 배 이상 1400ms 주위

pbl = GdkPixbuf.PixbufLoader() 
pbl.write(data, len(data)) 
pbl.close() 
pb = pbl.get_pixbuf() 

이 평균.

여기 뭔가 잘못 되었나요?

+2

당신이 시간이 소비되는 위치를 확인할 수 파이썬 프로파일 링 도구를 사용하여 고려 유무 : 여기

소스입니까? –

+0

Pixbufloader 닫기 호출은 현재 내 런타임의 94 %이며, 그 호출 내에서 자세한 내용을 얻지는 못합니다. –

답변

2

내 생각 엔 뭔가 잘못하고있는 것 같습니다. 나는 libjpeg-turbo를 gdk.PixbufLoader와 비교했을 때 속도 차이가 거의 발견되지 않았다. 내가 사용한 코드는 다음과 같습니다. libjpeg 터보를 들어

(jpegload.c) : 파이썬 GDK를 들어

#include <assert.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/time.h> 

#include <jpeglib.h> 

void decompress(FILE* fd) 
{ 
    JSAMPARRAY buffer; 
    int row_stride; 
    struct jpeg_decompress_struct cinfo; 
    struct jpeg_error_mgr jerr; 
    cinfo.err = jpeg_std_error(&jerr); 
    jpeg_create_decompress(&cinfo); 
    jpeg_stdio_src(&cinfo, fd); 
    jpeg_read_header(&cinfo, TRUE); 
    jpeg_start_decompress(&cinfo); 
    row_stride = cinfo.output_width * cinfo.output_components; 
    buffer = (*cinfo.mem->alloc_sarray) 
       ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); 
    while (cinfo.output_scanline < cinfo.output_height) { 
    (void) jpeg_read_scanlines(&cinfo, buffer, 1); 
    } 
    jpeg_finish_decompress(&cinfo); 
    jpeg_destroy_decompress(&cinfo); 
} 

int main(int argc, char** argv) 
{ 
    long len; 
    FILE *fd; 
    unsigned char *buf; 
    struct timeval start, end; 
    int i; 
    const int N = 100; 
    int delta; 

    /* read file to cache it in memory */ 
    assert(argc == 2); 
    fd = fopen(argv[1], "rb"); 
    fseek(fd, 0, SEEK_END); 
    len = ftell(fd); 
    rewind(fd); 
    buf = malloc(len); 
    assert(buf != NULL); 
    assert(fread(buf, 1, len, fd) == len); 

    gettimeofday(&start, NULL); 
    for(i = 0; i < N; i++) { 
    rewind(fd); 
    decompress(fd); 
    } 
    gettimeofday(&end, NULL); 
    if(end.tv_sec > start.tv_sec) { 
    delta = (end.tv_sec - start.tv_sec - 1) * 1000; 
    end.tv_usec += 1000000; 
    } 
    delta += (end.tv_usec - start.tv_usec)/1000; 
    printf("time spent in decompression: %d msec\n", 
     delta/N); 
} 

(gdk_load.py) :

import sys 
import gtk 
import time 

def decompress(data): 
    pbl = gtk.gdk.PixbufLoader() 
    pbl.write(data, len(data)) 
    pbl.close() 
    return pbl.get_pixbuf() 

data = open(sys.argv[1]).read() 

N = 100 
start = time.time() 
for i in xrange(N): 
    decompress(data) 
end = time.time() 
print "time spent in decompression: %d msec" % int((end - start) * 1000/N) 

테스트 실행 결과 :

$ gcc jpegload.c -ljpeg 
$ ./a.out DSC_8450.JPG 
time spent in decompression: 75 msec 
$ python gdk_load.py DSC_8450.JPG 
time spent in decompression: 75 msec 
$ identify DSC_8450.JPG 
DSC_8450.JPG JPEG 3008x2000 3008x2000+0+0 8-bit DirectClass 2.626MB 0.000u 0:00.019 

편집 : 이번에 gi.repostiroy을 사용하는 다른 테스트 :

import sys 
import time 
from gi.repository import GdkPixbuf 

def decompress(filename): 
    pb = GdkPixbuf.Pixbuf.new_from_file(filename) 
    return pb 

N = 100 
start = time.time() 
for i in xrange(N): 
    decompress(sys.argv[1]) 
end = time.time() 
print "time spent in decompression: %d msec" % int((end - start) * 1000/N) 

그리고 결과 : gi.repository를 사용

$ python gi_load.py DSC_8450.JPG 
time spent in decompression: 74 msec 

GdkPixbuf.PixbufLoader 정말 훨씬 느린 "순수"gtk.gdk 다음이다.코드 :

import sys 
import time 
from gi.repository import GdkPixbuf 

def decompress(data): 
    pbl = GdkPixbuf.PixbufLoader() 
    pbl.write(data, len(data)) 
    pbl.close() 
    return pbl.get_pixbuf() 

data = bytearray(open(sys.argv[1]).read()) 

N = 100 
start = time.time() 
for i in xrange(N): 
    decompress(data) 
end = time.time() 
print "time spent in decompression: %d msec" % int((end - start) * 1000/N) 

결과 :

$ python gi_load.py DSC_8450.JPG 
time spent in decompression: 412 msec 

그러나 GdkPixbuf.Pixbuf.new_from_file 빨리도 gi.repository를 사용하여 순수한 C 버전을 작동, 그래서 당신은 여전히 ​​하나 뭔가 잘못하고, 또는 너무 많이 기대하고있다.

+0

GObject에서 파일에서 읽은 데이터가 작동하지 않아 bytearray 호출이 필요하지 않으므로 문제의 원인인지 궁금합니다. –

+0

"GObject 아래"란 무엇을 의미합니까? gobject I/O 코드를 사용하여 파일을 읽으십니까? – abbot

+0

gtk를 가져 오기 대신 gi.repository에서 Gtk를 가져 오는 중입니다. 분명히 이것은 "새로운 GObject"방법입니다. pygtk 사이트는 새로운 코드를 권장합니다. 실제로는 모든 것이 pygtk 예제와 미묘하게 다릅니다. 편물. –

1

저는 pygtk로 작은 이미지 뷰어를 개발했습니다. PixbufLoader를 사용하지만 write() 당 N 바이트 만 공급합니다. idle_add()와 함께 백그라운드에서 이미지를로드 할 수 있지만 응용 프로그램은 여전히 ​​사용자 입력에 응답합니다. http://guettli.sourceforge.net/gthumpy/src/ImageCache.py

+0

흥미 롭습니다. 현재 Pixbufloader의 닫기 호출에 큰 (2 초) 지연이 있습니다. 불행히도 나는 비슷한 문제가 있는지보기 위해 너를 도망 칠 수 없었다. –

관련 문제