Подтвердить что ты не робот

Pickle быстрее, чем cPickle с числовыми данными?

В настоящее время я работаю над поиском изображений с помощью Python. Ключевые точки и дескрипторы, извлеченные из изображения в этом примере, представлены как numpy.array s. Первая форма (2000, 5) и последняя формы (2000, 128). Оба содержат только значения dtype=numpy.float32.

Итак, мне было интересно, какой формат использовать для сохранения моих извлеченных ключевых точек и дескрипторов. То есть Я всегда сохраняю 2 файла: один для ключевых точек и один для дескрипторов - это один шаг в моих измерениях. Я сравнивал pickle, cPickle (оба с протоколом 0 и 2) и двоичный формат NumPy .pny, и результаты меня действительно путают:

enter image description here

Я всегда думал, что cPickle должен быть быстрее, чем модуль pickle. Но особенно время загрузки с протоколом 0 действительно торчит в результатах. У кого-нибудь есть объяснение? Это потому, что я использую только числовые данные? Кажется странным...

PS: В моем коде я в основном зацикливаю 1000 раз (number=1000) по каждой технике и усредняет измеренное время в конце:

    timer = time.time

    print 'npy save...'
    t0 = timer()
    for i in range(number):
        numpy.save(npy_kp_path, kp)
        numpy.save(npy_descr_path, descr)
    t1 = timer()
    results['npy']['save'] = t1 - t0

    print 'npy load...'
    t0 = timer()
    for i in range(number):
        kp = numpy.load(npy_kp_path)
        descr = numpy.load(npy_descr_path)
    t1 = timer()
    results['npy']['load'] = t1 - t0


    print 'pickle protocol 0 save...'
    t0 = timer()
    for i in range(number):
        with open(pkl0_descr_path, 'wb') as f:
            pickle.dump(descr, f, protocol=0)
        with open(pkl0_kp_path, 'wb') as f:
            pickle.dump(kp, f, protocol=0)
    t1 = timer()
    results['pkl0']['save'] = t1 - t0

    print 'pickle protocol 0 load...'
    t0 = timer()
    for i in range(number):
        with open(pkl0_descr_path, 'rb') as f:
            descr = pickle.load(f)
        with open(pkl0_kp_path, 'rb') as f:
            kp = pickle.load(f)
    t1 = timer()
    results['pkl0']['load'] = t1 - t0


    print 'cPickle protocol 0 save...'
    t0 = timer()
    for i in range(number):
        with open(cpkl0_descr_path, 'wb') as f:
            cPickle.dump(descr, f, protocol=0)
        with open(cpkl0_kp_path, 'wb') as f:
            cPickle.dump(kp, f, protocol=0)
    t1 = timer()
    results['cpkl0']['save'] = t1 - t0

    print 'cPickle protocol 0 load...'
    t0 = timer()
    for i in range(number):
        with open(cpkl0_descr_path, 'rb') as f:
            descr = cPickle.load(f)
        with open(cpkl0_kp_path, 'rb') as f:
            kp = cPickle.load(f)
    t1 = timer()
    results['cpkl0']['load'] = t1 - t0


    print 'pickle highest protocol (2) save...'
    t0 = timer()
    for i in range(number):
        with open(pkl2_descr_path, 'wb') as f:
            pickle.dump(descr, f, protocol=pickle.HIGHEST_PROTOCOL)
        with open(pkl2_kp_path, 'wb') as f:
            pickle.dump(kp, f, protocol=pickle.HIGHEST_PROTOCOL)
    t1 = timer()
    results['pkl2']['save'] = t1 - t0

    print 'pickle highest protocol (2) load...'
    t0 = timer()
    for i in range(number):
        with open(pkl2_descr_path, 'rb') as f:
            descr = pickle.load(f)
        with open(pkl2_kp_path, 'rb') as f:
            kp = pickle.load(f)
    t1 = timer()
    results['pkl2']['load'] = t1 - t0


    print 'cPickle highest protocol (2) save...'
    t0 = timer()
    for i in range(number):
        with open(cpkl2_descr_path, 'wb') as f:
            cPickle.dump(descr, f, protocol=cPickle.HIGHEST_PROTOCOL)
        with open(cpkl2_kp_path, 'wb') as f:
            cPickle.dump(kp, f, protocol=cPickle.HIGHEST_PROTOCOL)
    t1 = timer()
    results['cpkl2']['save'] = t1 - t0

    print 'cPickle highest protocol (2) load...'
    t0 = timer()
    for i in range(number):
        with open(cpkl2_descr_path, 'rb') as f:
            descr = cPickle.load(f)
        with open(cpkl2_kp_path, 'rb') as f:
            kp = cPickle.load(f)
    t1 = timer()
    results['cpkl2']['load'] = t1 - t0 
4b9b3361

Ответ 1

(двоичное представление) числовых данных ndarray маринован как одна длинная строка. Похоже, что cPickle действительно намного медленнее, чем pickle при рассылке больших строк из файлов протокола 0. Зачем? Я предполагаю, что pickle использует хорошо настроенные строковые алгоритмы из стандартной библиотеки, а cPickle отстает.

Наблюдение выше - игра с Python 2.7. Python 3.3, который автоматически использует расширение C, быстрее, чем любой из модулей на Python 2.7, поэтому проблема была исправлена.