Как работать с numba в питоне с использованием ClickHouse?
Пытаюсь работать с numba в питоне и не получается использовать курсор базы данных. Использую
request = client.execute_iter(base_req), причем создание курсора я пытался выносить в отдельную функцию, для которой не применял декоратор @njit, не помогло. Искал в документации numba clickhouse - ничего нет.
На этот код я получаю сообщение:
This error may have been caused by the following argument(s):
- argument 0: cannot determine Numba type of <class 'clickhouse_driver.client.Client'>
По сути же, я в итераторе буду идти по этому курсору и получать обычные кортежи из двух элементов, с которыми numba работает. Как работать с numba, используя ClickHouse? Описание задачи: происходит запрос к БД, из которой выгружаются кортежи из двух элементов, первый элемент - строка, второй число. Генерируется словарь, в качестве ключа которого выступают строки, а значения - списки из чисел, то есть происходит некая группировка по строкам. На текущий момент скорость заполнения словаря составляет примерно 500 000 строк в секунду.
d = defaultdict(list)
request = client.execute_iter(base_req)
{d[_i[1].lower()].append(_i[0]) for _i in tqdm.tqdm(request) if _i[0] not in d[_i[1].lower()]}
Запрос, к сожалению, показать не могу. Примерный результат вывода запроса: ("string", 5).
Ответы (1 шт):
Ну вот теперь хоть есть какой-то предмет (код) для разговора:
{d[_i[1].lower()].append(_i[0]) for _i in tqdm.tqdm(request) if _i[0] not in d[_i[1].lower()]}
- Если вас интересует скорость - не используйте
tqdmво внутренних циклах обработки! Если у вас есть какой-то внешний цикл - там можете использовать. А если вы оборачиваете самый внутренний цикл вtqdm- будьте готовы к значительному замедлению работы кода (вполне возможно, что всё замедление даёт вам именноtqdm). Возможно, с тех пор, как я всё это замерял прошло время и библиотеку немного улучшили, но работа сGUIвсегда медленная и это также подтверждает мой личный опыт, чтоtqdmзамедляет скорость работы кода в несколько раз. - У вас может по два раза осуществляться доступ к
d[_i[1].lower()], лучше занесите эту ссылку на список в отдельную переменную и делайте проверку и добавление через эту переменную. И функцияlowerтоже может работать не очень быстро, так что тут убьёте сразу двух зайцев. - Чтобы сделать изменение кода из п.2, вам видимо нужно отказаться от использования
включения множестваили что там у вас получилось через конструкцию{ comprehension }, тем более, что результат его вы всё-равно не используете, просто зря расходуя ресурсы на его генерацию - у вас получается там создаётся множество из элементовNone(потому чтоlist.appendвозвращаетNone), взятых в количестве элементов, возвращённых запросом. Всё это схлопывается в итоге в пустое множество. Зачем эта лишняя работа? Списковые (и прочие) включения - штука удобная и их можно и нужно использовать для выполнения небольших работ, но не в том, случае, когда речь идёт о миллионах записей и дорога каждая микросекунда, в этом случае надо тщательно смотреть, какой подход будет оптимальнее.
Так что предлагаю написать обычный прямой код, померить, с какой скоростью он будет работать и потом уже, если надо, думать дальше насчёт Numba, lru_cache или каких-то других улучшений:
for _i in request:
l = d[_i[1].lower()]
v = _i[0]
if v not in l:
l.append(v)
Кстати, вопрос - важен ли вам порядок элементов в списке, лежащем в словаре? Если нет, то сходу могу предложить использовать defaultdict(set) и l.add(v), проверка на наличие элемента в коллекции будет работать значительно быстрее.
d = defaultdict(set)
for _i in request:
l = d[_i[1].lower()]
v = _i[0]
if v not in l:
l.add(v)