ncalls
имеет отношение только к той степени, в которой сравнение чисел с другими значениями, такими как количество символов / полей / строк в файле, может выделить аномалии; tottime
и cumtime
- это то, что действительно имеет значение. cumtime
- это время, потраченное на функцию / метод , включая время, потраченное на функции / методы, которые она вызывает; tottime
- это время, потраченное на функцию / метод , исключая время, потраченное на функции / методы, которые она вызывает.
Я считаю полезным сортировать статистику по tottime
и снова по cumtime
, а не по name
.
bgchar
определенно относится к выполнению сценария и не имеет значения, поскольку занимает 13,9 с из 13,5; что 8,9 секунды НЕ включают время в вызываемых им функциях / методах! Внимательно прочитайте, что @Lie Ryan говорит о модульности вашего скрипта в функции, и реализуйте его советы. Аналогично тому, что говорит @jonesy.
string
упоминается, потому что вы import string
и используете его только в одном месте: string.find(elements[0], 'p')
. В другой строке вывода вы заметите, что string.find был вызван только один раз, так что это не проблема с производительностью при выполнении этого скрипта. ОДНАКО: Вы используете str
методы везде. В настоящее время функции string
устарели и реализуются путем вызова соответствующего метода str
. Вы бы лучше написали elements[0].find('p') == 0
для точного, но более быстрого эквивалента и могли бы использовать elements[0].startswith('p')
, что избавило бы читателей от сомнений, действительно ли это == 0
будет == -1
.
Четыре метода, упомянутых @Bernd Petersohn, занимают всего 3,7 секунды из общего времени выполнения 13,541 секунды. Прежде чем беспокоиться об этом, разбейте ваш скрипт на функции, снова запустите cProfile и отсортируйте статистику по tottime
.
Обновление после пересмотра вопроса с измененным сценарием:
"" "Вопрос: что я могу сделать с операциями объединения, разделения и записи, чтобы уменьшить видимое влияние, которое они оказывают на производительность этого сценария?" "
А? Эти 3 вместе занимают 2,6 секунды из 13,8. Ваша функция parseJarchLine занимает 8,5 секунд (что не включает время, затраченное вызываемыми ей функциями / методами. assert(8.5 > 2.6)
Бернд уже указал вам на то, что вы могли бы сделать с ними. Вы напрасно разделяете строку, чтобы снова присоединиться к ней при ее записи. Вам нужно осмотреть только первый элемент. Вместо elements = line.split('\t')
сделайте elements = line.split('\t', 1)
и замените '\t'.join(elements[1:])
на elements[1]
.
Теперь давайте погрузимся в тело parseJarchLine. Количество использований в источнике и способ использования встроенной функции long
поражают. Также удивительным является тот факт, что long
не упоминается в выходных данных cProfile.
Зачем вам вообще нужно long
? Файлы больше 2 Гб? Хорошо, тогда вам нужно учесть, что, поскольку в Python 2.2 переполнение int
вызывает повышение до long
вместо вызова исключения. Вы можете воспользоваться более быстрым выполнением арифметики int
. Вы также должны учитывать, что выполнение long(x)
, когда x
уже очевидно, long
- пустая трата ресурсов.
Вот функция parseJarchLine с изменениями удаления отходов, помеченными [1], и изменениями, внесенными в int, помеченными [2]. Хорошая идея: вносить изменения небольшими шагами, перепроверять, перепрофилировать.
def parseJarchLine(chromosome, line):
global pLength
global lastEnd
elements = line.split('\t')
if len(elements) > 1:
if lastEnd != "":
start = long(lastEnd) + long(elements[0])
# [1] start = lastEnd + long(elements[0])
# [2] start = lastEnd + int(elements[0])
lastEnd = long(start + pLength)
# [1] lastEnd = start + pLength
sys.stdout.write("%s\t%ld\t%ld\t%s\n" % (chromosome, start, lastEnd, '\t'.join(elements[1:])))
else:
lastEnd = long(elements[0]) + long(pLength)
# [1] lastEnd = long(elements[0]) + pLength
# [2] lastEnd = int(elements[0]) + pLength
sys.stdout.write("%s\t%ld\t%ld\t%s\n" % (chromosome, long(elements[0]), lastEnd, '\t'.join(elements[1:])))
else:
if elements[0].startswith('p'):
pLength = long(elements[0][1:])
# [2] pLength = int(elements[0][1:])
else:
start = long(long(lastEnd) + long(elements[0]))
# [1] start = lastEnd + long(elements[0])
# [2] start = lastEnd + int(elements[0])
lastEnd = long(start + pLength)
# [1] lastEnd = start + pLength
sys.stdout.write("%s\t%ld\t%ld\n" % (chromosome, start, lastEnd))
return
Обновление после вопроса о sys.stdout.write
Если закомментированное вами утверждение было чем-то похожим на оригинальное:
sys.stdout.write("%s\t%ld\t%ld\t%s\n" % (chromosome, start, lastEnd, '\t'.join(elements[1:])))
Тогда ваш вопрос ... интересен. Попробуйте это:
payload = "%s\t%ld\t%ld\t%s\n" % (chromosome, start, lastEnd, '\t'.join(elements[1:]))
sys.stdout.write(payload)
Теперь закомментируйте оператор sys.stdout.write
...
Кстати, кто-то упомянул в комментарии о разбиении этого на более чем одну запись ... Вы рассматривали это? Сколько байт в среднем в элементах [1:]? В хромосоме?
=== смена темы: меня беспокоит, что вы инициализируете lastEnd
вместо ""
, а не в ноль, и что никто не прокомментировал это.В любом случае, вы должны исправить это, что допускает довольно резкое упрощение и добавление других предложений:
def parseJarchLine(chromosome, line):
global pLength
global lastEnd
elements = line.split('\t', 1)
if elements[0][0] == 'p':
pLength = int(elements[0][1:])
return
start = lastEnd + int(elements[0])
lastEnd = start + pLength
sys.stdout.write("%s\t%ld\t%ld" % (chromosome, start, lastEnd))
if elements[1:]:
sys.stdout.write(elements[1])
sys.stdout.write(\n)
Теперь я так же обеспокоен двумя глобальными переменными lastEnd
и pLength
-функция parseJarchLine теперь настолько мала, что ее можно сложить обратно в тело ее единственного вызывающего объекта, extractData
, который сохраняет две глобальные переменные и вызовы функции gazillion.Вы также можете сэкономить на поиске gazillion sys.stdout.write
, поставив write = sys.stdout.write
один раз перед extractData
и используя его вместо этого.
Кстати, скрипт тестирует для Python 2.5 или выше;Вы пробовали профилирование на 2.5 и 2.6?