#python #yield
Вопрос:
У меня есть сетевая структура, использующая protobuf для кодирования передаваемых данных и использования generator.send(request)
и next_request = yield(reply)
конструкций.
Теперь я сталкиваюсь с проблемами производительности, когда время между generator.send(reuqest)
возвращением и next_request = yield(reply)
возвращением составляет почти секунду. Кодовая база огромна, поэтому у меня нет минимального тестового случая. Но вот кодовая последовательность, которую я измеряю:
data = huge_big_dictionary_of_dictionaries
logger.info("sending to generator")
generator.send(data)
# other coroutine
data = yield(...)
logger.info("got data")
Что я получаю, так это:
2021-09-13 14:16:26,427 INFO Node send to generator
2021-09-13 14:16:27,351 INFO Handler got data
Данные представляют собой большое дерево, где каждый узел представляет собой словарь, а листья-пары ключевых значений (строки). Верхний уровень содержит ~9000 записей и около миллиона пар значений ключей. Он большой. Строка протобуфа составляет 30 мбАйТ.
Теперь я предположил send/yield
, что он просто передаст указатель на структуру и практически не займет времени. Но, похоже, это не так.
Что же send/yield
делать? Делает ли это глубокую копию всей структуры? Нужно ли увеличивать количество ссылок на каждый узел для сборщика мусора? Как мне сделать send/yield
пробег в постоянное время?
Комментарии:
1. Нет, Python никогда не копирует неявно, как это. Но передается ли что — то по сети фреймворком? Да, под капотом вы просто отправляете ссылку (указатель PyObject в CPython)
2. Строка protobuf отправляется по сети и принимается платформой. Анализ строки в данные python занимает около полсекунды, а затем отправляется генератору. Создание сетей и синтаксический анализ происходят до
logger.info()
.3. Это накладные расходы сети, а не часть
yield
ее самой.4. @Barмар Преобразование и создание сетей происходит до того, как loogger.info. Все данные там и проанализированы, прежде чем я позвоню
generator.send
.5. Какая часть этого передается по сети?