Многопоточность Bigquery Python API не повышает производительность - PullRequest
0 голосов
/ 27 июня 2018

Я использую Python BigQuery API для отображения содержимого таблицы, а затем обрабатываю данный ответ JSON.

  • 100 000 запись с основным потоком занимает приблизительно 30 секунд
  • 10000 запись с основным потоком занимает приблизительно 4 секунды
  • 100 000 записей с 10 потоками или 5 занимает примерно 20 секунд .

другая полезная информация.

для 100 000 записей с основным потоком.

  • Результат выборки элемента списка (вызовы REST) ​​- 25 секунд
  • результат разбора - 5 секунд
  • результат записи - 2 секунды

Разве это не должно занимать меньше времени?

Кто-нибудь, пожалуйста, дайте мне знать, в чем причина этой задержки производительности?

def _get_values(val):
    if isinstance(val, datetime.datetime):
        return str(val)
    else:
        return val

def map_schema(row):
    row_dict = {}
    values = row.values()
    field_to_index = row._xxx_field_to_index
    for field, index in field_to_index.iteritems():
        row_dict[str(field)] = _get_values(values[index])
    return row_dict

def write_json(file, row):
    file.write(json.dumps(row))


def _save_rows(table, start_index, max_row, file):
    rows = client.list_rows(table, max_results=max_row, start_index=start_index)
    for row in rows:
        processedRow = map_schema(row)
        write_json(file, processedRow)

def run():
    threads = []
    dataset_ref = client.dataset('hacker_news', project='bigquery-public-data')
    table_ref = dataset_ref.table('comments')
    table = client.get_table(table_ref)  # API call
    import time
    start = time.time()
    output_file = open("temp_t.json", "a")

    total_rows = 100000
    total_threads = 10
    max_row = total_rows/total_threads

    # 10 threads takes ~ 20 seconds
    # 5 threads takes the same ~ 20 seconds
    files = []
    for index in range(0, total_rows, max_row):
        file_name = "%s.json" % index
        files.append(open(file_name, "a"))
        threads.append(threading.Thread(target=_save_rows, args=(table, index, max_row, output_file)))

    for thread in threads:
        thread.start()
    for thread in threads:
        thread.join()
    for file in files:
        file.close()


    # takes ~ 30 seconds
    # _save_rows(table, 0, 100000, output_file)

    # takes ~ 4 seconds
    # _save_rows(table, 0, 10000, output_file)

    output_file.close()
    print "total time = %f" % (time.time() - start)

run()

1 Ответ

0 голосов
/ 13 июня 2019

Нет, вы не должны ожидать каких-либо улучшений многопоточности в Python. Как многие уже упоминали, это связано с поведением GIL. Поскольку запрос данных является задачей, требующей интенсивного использования ЦП, многопоточность может даже ухудшить ее, поскольку она действительно полезна только для сложных задач ввода-вывода.

Тем не менее, многопроцессорная обработка в Python намного лучше с задачами, интенсивно использующими процессор, поэтому я бы попробовал это. Это связано с тем, что многопроцессорная обработка - это параллелизм, а многопоточность просто создает иллюзию параллелизма (одновременно выполняется только один поток, поэтому он параллелен).

...