Если это внешний модуль, то есть вероятность что он отпускает GIL и тогда его можно эффективно гонять через ThreadPoolExecutor, а иначе ProcessPoolExecutor в помощь, у обоих одинаковый асинхронный интерфейс.
Сергей Соколов, база в памяти - это redis/memcached или что-то самописное?
А чем программа занимается, раз она так активно CPU кушает? Может есть смысл именно на это место обратить внимание, вместо выдумывания распределённой системы?
Я в итоге остановился просто на том, что использую один класс, который умеет делать нужные действия с базой, обеспечивая интерфейс в терминах бизнес-логики. Делать это из самих объектов с данными — странная идея, как по мне.
Понадобится вам метрики по скорости ответа базы писать и куда вы их запихнёте? Не оборачивать же каждое использование в with Timer, код получается нечитаемый.
Даже более того, любое действие с этими объектами нужно будет оборачивать в try except, потому что там под капотом сетевые операции.
Я знаю, что есть довольно много любителей ORM и даже сам таким был, но уж очень много с ними геморроя, когда нужно сделать что-то хоть чуть-чуть не так, как предложено. Они тут же из удобного инструмента превращаются в агрессивного ежа с ядовитыми иглами.
Сергей Паньков, примерно всё проще брокеров очередей, имхо, согласованные распределённые системы простыми не бывают :)
Я работал только с Kafka и RabbitMQ — оба проекта с кучей артефактов и огромной кодовой базой: кафке нужен отдельный ZooKeeper, который несмотря на проверку временем, всё ещё требует от пользовательского кода умения восстановить все данные с нуля, поскольку в случае сбоев это самый простой способ его починить; у кролика блокирующая репликация, которая регулярно стреляет под нагрузкой.
Без репликации они неплохо работают, да, но какой смысл тогда говорить о надёжности?
Главное, что совокупная сложность системы при их использовании возрастает многократно. Если данные простые и нужно только какие-нибудь счётчики вести, то я бы предложил даже от полноценной базы отказаться в пользу какого-нибудь redis.
z0ng, отдельный поток для работы с базой и threading.Queue не решают эту проблему? При таком подходе мы практически бесплатно получаем буферизацию записи.
Поймите меня правильно, асинхронность — отличный инструмент, но там тоже полно подводных камней, стоит всё-таки инструменты под задачу подбирать, имхо :)
Про персистентные очереди, предложенные Сергей Паньков, я вообще молчу, можно заодно предложить развернуть kubernetes и нанять команду сисадминов, чтобы процесс перезапускать.
Ищите самое простое из всё ещё работающих решений, усложнить всегда успеете.
Я не берусь говорить за те языки на которых не писал, но худо-бедно могу рассказать про асинхронную модель вычислений на Python и Go.
Python: у нас есть один процесс в рамках которого тысячи запущенных корутин могут одновременно ждать, но в каждый момент времени выполняется ровно одна из них.
Присутствует планировщик — event loop, он передаёт управление следующей готовой к исполнению корутине, но ему мы из текущей корутины должны явно отдать управление с помощью инструкции await.
Go: присутствует несколько процессов и явный способ создавать горутины, с помощью инструкции go, это приводит лишь к её планированию, она будет назначена на первый освободившийся процесс. Что интересно, так это неявная отдача управления, в Go нет аналога инструкции await из Python, язык сам определяет где это управление нужно отдать.
nikvay, это промышленный стандарт, в реальной жизни ровно так эти задачи и решаются.
Что касается "классификации котов", так это основа основ — сначала сеть учится распознавать цвета и градиенты, потом границы, затем текстуры.
Когда вы дообучаете готовую нейросеть, вы кардинально упрощаете себе задачу и вам становится не нужен огромный массив данных для того, чтобы научить сеть распознавать базовые элементы, которые одинаковы для всех изображений.
"Коты" — достаточно высокоуровневое понятие на самом деле :)
Антон Рейтаровский, например чтобы сделать системные вызовы неблокирующими, или если вы работаете с библиотеками, отпускающими GIL на время вычислений, и хотите распараллелить работу.
Если это внешний модуль, то есть вероятность что он отпускает GIL и тогда его можно эффективно гонять через ThreadPoolExecutor, а иначе ProcessPoolExecutor в помощь, у обоих одинаковый асинхронный интерфейс.