2016-08-29 3 views
1

Я запускаю алгоритм, который считывает документ excel по строкам и выталкивает строки на SQL Server с использованием Python. Я хотел бы напечатать какой-то прогресс через цикл. Я могу подумать о двух очень простых вариантах, и я хотел бы знать, какой из них более легкий и почему. Вариант А:Эффективность при печати обновлений прогресса, print x vs if x% y == 0: print x

for x in xrange(1, sheet.nrows): 
    print x 
    cur.execute() # pushes to sql 

Вариант B:

for x in xrange(1, sheet.nrows): 
    if x % some_check_progress_value == 0: 
     print x 
    cur.execute() # pushes to sql 

У меня есть ощущение, что второй один будет более эффективным, но только для более масштабных программ. Есть ли способ вычислить/определить это?

+5

Я не думаю, что вам следует беспокоиться об эффективности этого. Что еще более важно, так это то, что первый будет заполнять ваш экран счетчиками, что может быть чрезмерным, в то время как второе сообщит вам, что программа продвигается без спама. – Barmar

+0

Вы также можете напечатать '.' Для каждой записи без новой строки, а затем распечатать новую строку для каждой записи 'some_progress_value'. – Barmar

+3

Я не думаю, что эффективность здесь - настоящая цель; самой эффективной задачей было бы вообще не печатать обновления. Вопрос в том, как долго вы хотите, чтобы пользователь смотрел на неизменный экран? –

ответ

1

Я один из разработчиков tqdm, a Python progress bar, который старается быть максимально эффективным, предоставляя как можно больше автоматических функций.

Самый большой снимок, который у нас был, был действительно I/O: печать на консоль/файл/что угодно.

Но если ваша петля плотная (более 100 итераций/секунд), то бесполезно печатать каждые, вы должны точно напечатать только 1/10 обновлений, и пользователь не увидит никакой разницы , в то время как ваш бар будет в 10 раз меньше накладных расходов (быстрее).

Чтобы исправить это, мы сначала добавили параметр mininterval, который обновлял дисплей только каждые x секунд (что по умолчанию составляет 0,1 секунды, человеческий глаз не может видеть ничего быстрее, чем это). Нечто подобное:

import time 

def my_bar(iterator, mininterval=0.1) 
counter = 0 
last_print_t = 0 
for item in iterator: 
    if (time.time() - last_print_t) >= mininterval: 
     last_print_t = time.time() 
     print_your_bar_update(counter) 
    counter += 1 

Это будет в основном устранить проблему, как ваш бар всегда будет иметь постоянный дисплей накладных расходов, которая будет все более и более незаметными у вас есть большие итераторы.

Если вы хотите продолжить оптимизацию, time.time() также является операцией ввода-вывода и, следовательно, имеет большую стоимость, чем простые инструкции Python. Чтобы избежать этого, вы хотите, чтобы свести к минимуму звонки вы делаете в time.time(), вводя новую переменную: miniters, который является минимальное количество итераций вы хотите, чтобы пропустить еще до проверки времени:

import time 

def my_bar(iterator, mininterval=0.1, miniters=10) 
counter = 0 
last_print_t = 0 
last_print_counter = 0 
for item in iterator: 
    if (counter - last_print_counter) >= miniters: 
     if (time.time() - last_print_t) >= mininterval: 
      last_print_t = time.time() 
      last_print_counter = counter 
      print_your_bar_update(counter) 
    counter += 1 

Вы можете видеть, что miniters аналогичен вашему модулю Option B, но он лучше приспособлен как добавленный слой с течением времени, потому что время более легко настраивается.

С помощью этих двух параметров вы можете вручную настроить текущий индикатор выполнения, чтобы сделать его наиболее эффективным для вашего цикла.

Однако miniters (или модуль) сложно использовать для работы в целом для всех без ручной настройки, вам нужно сделать хорошие предположения и умные трюки, чтобы автоматизировать этот фитинг. Это одна из основных текущих работ, которые мы делаем на tqdm. В основном, мы делаем то, что мы пытаемся вычислить miniters равным mininterval, так что проверка времени больше не требуется. Этот параметр пинки в после mininterval Automagic сработал, что-то вроде этого:

from __future__ import division 
import time 

def my_bar(iterator, mininterval=0.1, miniters=10, dynamic_miniters=True) 
counter = 0 
last_print_t = 0 
last_print_counter = 0 
for item in iterator: 
    if (counter - last_print_counter) >= miniters: 
     cur_time = time.time() 
     if (cur_time - last_print_t) >= mininterval: 
      if dynamic_miniters: 
       # Simple rule of three 
       delta_it = counter - last_print_counter 
       delta_t = cur_time - last_print_t 
       miniters = delta_it * mininterval/delta_t 
      last_print_t = cur_time 
      last_print_counter = counter 
      print_your_bar_update(counter) 
    counter += 1 

Существуют различные способы, чтобы вычислить miniters автоматически, но, как правило, вы хотите обновить его, чтобы соответствовать mininterval.

Если вы заинтересованы в рытье больше, вы можете проверить dynamic_miniters внутренние параметры, maxinterval и в experimental monitoring thread в tqdm project.

3

Я новичок, поэтому не могу комментировать. «Ответ» может быть излишним, но это все, что я могу сделать сейчас.

Моя любимая вещь для этого: tqdm. Он минимально инвазивный, как по коду, так и по выходным, и он выполняет свою работу.

1

Использование проверки модуля (счетчик% N == 0) является почти бесплатным сравнением печати и отличным решением, если вы запускаете высокочастотную итерацию (много журналов). Специально, если вам не нужно печатать для каждой итерации, но вам нужна некоторая обратная связь.

Смежные вопросы