Форум сайта python.su
День добрый, господа хорошие.
Ломаю голову. подскажите куда копать.
Суть вопроса: есть python 3.3.6, есть небольшой скрипт. суть скрипта - тянет выборку (датасет1 - только чтение) с MSSQL базы (скажем 20 млн строк). для каждой строки производит сравнение по непростым условиям и в итоге может создать на каждую запись первой выборки - по 2-5 записей (датасет2 - запись), суммирует полученные и сохраняет запись в датасет3 (запись) со значением суммы.
в одном потоке на машине с ксеоном потребляет всего 10-20% ЦПУ и работает достаточно долго (за 8-10 часов). Хотелось бы распараллелить. так как в основном винда то multiprocessor вроде получается только.
Подскажите пожалуйста куда копать. для сохранения в базе, делал батчи инсерта по 500-1000 записей. т.е. готов собирать 500-1000 строк, оборачивать в лист и отсылать воркеру. но тогда получается каждый раз на инициализации/убийстве воркеров время тратится. пусть бы у каждого воркера был бы свой курсор и тянул данные по 500-1000 строк с главного процесса.
помогите пожалуйста советом как организовать.
Офлайн
DeesyНикак с виндой не связано.
так как в основном винда то multiprocessor
DeesyЭто при скольких доступных ядрах?
всего 10-20% ЦПУ
Офлайн
doza_andчитал что в cpython multithreading работает по-другому из-за реализации GIL. но увы доступны только машины под виндой и только стандартный cpython. сейчас установлен 3.3.4 (пардон, не 3.3.6) но подал заявку на установку последнего 3.6.5 ибо читал что с (насколько я помню) 3.4.Х добавили асинкио. возможно будет полезным для скидывания данных в базу.
Никак с виндой не связано.
doza_andпардон не дописал. на моей рабочей машине стоит зион с 6-ю ядрами (дополнительно х2 хайпертрединг итого 12) но при работе используется только 1 ядро на 10-20%. но в целом планировалось потом скрипт запускать на отдельной машине.
Это при скольких доступных ядрах?
Отредактировано Deesy (Май 22, 2018 12:47:10)
Офлайн
1 ядро на 10% ??? Ну тут распаралелливание не поможет вы ведь не по прозводительности CPU ограничены. Надо sql запрос оптимизировать и посмотреть как диск загружен.
А оптимизацию надо начинать с профилирования.
https://docs.python.org/3/library/debug.html
Офлайн
примерную хрень проводил отключив выемку данных с датасета1 и заменив на идентичные значения для списка.
увы по сиквелю я больше соображаю чем по питону. выборка с оптимизирована на максимум.
фетчу из датасета по 1 записи. ибо fetchall кмк не втянет 20 млн в память. может быть есть возможность фетчить буфером по 10к?
за линк спасибо, гляну.
Офлайн
DeesyЧто? не так точно не пойдет. Вы должны получить итератор, он не приводит к загрузке всего в память.
фетчу из датасета по 1 записи.
Офлайн
в обычный день может быть 20млн записей. в необычный в 3-4 раза больше.
def load_and_process_date(day): global process_start batch_total_started = time.perf_counter() batch_total = 0 batch_current = 0 row_list = [] batch_id = 0 with get_db_connection() as con: with get_db_cursor(con) as cur: sql = settings.sql_query['LOAD_ICF_DATA'] sql = sql % day cur.execute(sql) process_start = time.perf_counter() column_names = [col[0] for col in cur.description] batch_current_started = time.perf_counter() while True: row = cur.fetchone() if not row: break batch_total += 1 add_txn_data_row(row, day) # new_row = dict(zip(column_names, row)) # add_txn_data_row(new_row, day) if batch_current < settings.database['RowsInList']: batch_current += 1 if batch_current == settings.database['RowsInList']: commit_inserts(day) batch_id += 1 print("Avg/1M: {}, {}r/{:.4f} sec. TT: {:.4f} sec.".format(int( (time.perf_counter() - batch_total_started) * 1000000 / 60 / batch_total), batch_total, time.perf_counter() - batch_current_started, time.perf_counter() - batch_total_started)) batch_current = 0 batch_current_started = time.perf_counter() commit_inserts(day) return
Отредактировано Deesy (Май 23, 2018 22:42:46)
Офлайн
DeesyДля этого есть fetchmany.
фетчу из датасета по 1 записи. ибо fetchall кмк не втянет 20 млн в память. может быть есть возможность фетчить буфером по 10к?
doza_andЭто то-же самое по скорости, что и fetchone использовать.
Вы должны получить итератор, он не приводит к загрузке всего в память.
Офлайн
> тянет выборку (датасет1 - только чтение) с MSSQL базы (скажем 20 млн строк).
Почему пользуйтесь MSSQL? Если есть возможность используй PostgreSQL он даёт возможность делать хранимки на python-е и твой код можно будет запускать прямо на сервере что намного быстрее.
> в одном потоке на машине с ксеоном потребляет всего 10-20% ЦПУ
Ты упираешься в IO, по этому это нормально.
> Хотелось бы распараллелить.
Это делается при помощи модуля threading
Офлайн
почему MSSQL - потому, что увы не мой выбор (мне оракл больше по-душе). по-тому же почему я не особо могу (надеюсь что пока) поставить python отличный от версии 3.3.4 и т.д. увы тут не мои капризы и сделать-что-то кроме как “вылизать” код на питоне я не могу.
threading юзал, прироста не было. попробую на днях fetchmany() если оно работает с MSSQL отпишусь.
Офлайн