Почему для измерения времени выполнения функции лучше использовать time, а не datetime
Что проверяют
Понимаете ли вы, что длительность меряют монотонными часами, а не календарным временем. Вопрос простой на вид, но по нему видно, замеряли ли вы что-нибудь всерьёз или только вычитали два datetime.now().
Как отвечать
datetime.now() и time.time() это одни и те же настенные часы: они отвечают на вопрос «который час», а не «сколько прошло». Такие часы подводит служба синхронизации времени, их двигает смена часового пояса, и разность двух отметок может оказаться отрицательной или прыгнуть на секунды. Для замера нужен счётчик, который гарантированно не идёт назад.
import time
start = time.perf_counter()
do_work()
elapsed = time.perf_counter() - startЧто из модуля time для чего:
time.perf_counter(): монотонные часы с максимальным доступным разрешением, включают время ожидания. Выбор по умолчанию;time.perf_counter_ns(): то же самое в целых наносекундах, без потери разрядов при вычитании float;time.monotonic(): монотонные часы для таймаутов и пауз;time.process_time(): только процессорное время текущего процесса, без сна и ожидания ввода-вывода;timeit: для микрозамеров, сам делает прогоны и убирает часть шума.
Про datetime стоит сказать честно: он не хуже, он про другое. Дата, часовой пояс, запись момента события в базу это его работа, а интервал он считает теми же ненадёжными часами.
Где спотыкаются
Объясняют разницу точностью: мол, datetime грубее. Разрешение у них сопоставимое, обе функции берут системное время. Проблема в монотонности и в том, что календарные часы вправе прыгнуть.
Меряют один прогон и делают вывод. На быстрой функции один замер ловит планировщик, состояние кэша процессора и сборщик мусора. Нужно несколько повторов и минимум либо медиана, для этого и существует timeit.
Путают затраченное время с процессорным. Функция висит две секунды, process_time() показывает сотые доли, потому что всё ушло в ожидание сети. Вывод «код быстрый» здесь неверен, просто не тем счётчиком померили.