7

写真ブログへの投稿に使用するGTK(GObject)インターフェイスを備えたスクリプトがあります。

バックグラウンドスレッドに画像を読み込むことで、応答性を向上させようとしています。

バックグラウンドスレッドからGdkPixbufオブジェクトにデータを入力しようとしても、運が悪かったのですが、試したものはすべてしっかりと詰まっています。

そのため、別の方法として、バックグラウンドスレッドでファイルを読み取り、オンデマンドでGdkPixbufにプッシュすることを考えました。このアプローチは、私がひどく間違ったことをしているのではないかと思うような、驚くべき、かなり気のめいるようなパフォーマンス結果をもたらしました。

私はカメラから軽く圧縮されたjpegで遊んでいます、それらは約3.8mbである傾向があります。

元のブロッキング画像の読み込みは次のとおりです。

pb = GdkPixbuf.Pixbuf.new_from_file(image_file)

これは平均して約550ミリ秒で、大きくはありませんが、12枚の画像をフリックしたい場合は面倒です。

それから私はそれを分割しました、これが読んだファイルです:

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

これは平均15ミリ秒で、これは本当に素晴らしいことですが、15ミリ秒でファイルを読み取ることができれば、他の535ミリ秒は何に費やされているのでしょうか。

ちなみに、PixBufLoaderはそれ以外の場合はデータを受け入れないため、bytearray呼び出しが存在します。

そして、Pixbufロード:

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

これは平均して約1400msであり、Gtkにすべてを実行させるよりも約3倍長くなります。

私はここで何か間違ったことをしていますか?

4

2 に答える 2

2

私の推測:あなたは何か間違ったことをしています。libjpeg-turbo と gdk.PixbufLoader を比較したところ、速度の違いはほとんどありませんでした。私が使用したコードは以下のとおりです。

libjpeg-turbo (jpegload.c) の場合:

#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);
}

Python gdk (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)

そして結果:

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

gi.repository を使用する 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を使用しても純粋な C バージョンと同じくらい高速に動作するgi.repositoryため、何か間違ったことを行っているか、期待しすぎているかのどちらかです。

于 2011-05-03T12:52:33.220 に答える
1

私はpygtkで小さな画像ビューアを開発しました。私は PixbufLoader を使用していますが、write() ごとに N バイトしかフィードしません。idle_add() と組み合わせると、アプリケーションがユーザー入力に応答している間に、バックグラウンドで画像を読み込むことができます。

ソースは次のとおりです: http://guettli.sourceforge.net/gthumpy/src/ImageCache.py

于 2011-06-16T14:56:52.000 に答える