Как я могу ускорить python l oop с условием интервала времени - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть этот код, который довольно быстро делается, но в целом работает. Единственное, это работает вечно. Идея состоит в том, чтобы обновить 2 столбца в таблице, содержащей 1495748 строк, поэтому номер списка меток времени запрашивается в первую очередь. Для каждого значения обновления должно быть сделано сравнение, в котором временная метка должна быть в часовом интервале, который образован двумя временными метками, поступающими из API в двух разных диктовках. Есть ли способ немного ускорить процесс или, может быть, многопроцессорность?

Подсказка: db_ma c = db_connection к базе данных Postgres.

ответ выглядит следующим образом: {' meta ': {' source ':' National Oceani c and Atmospheri c Administration, Deutscher Wetterdienst '},' data ': [{' time ':' 2019-11-26 23:00:00 ',' time_local ':' 2019-11-27 00:00 ',' температура ': 8,3,' точка росы ': 5,9,' влажность ': 85,' осадков ': 0,' осадков_3 ': нет,' осадков_6 ': нет, «снежная глубина»: нет, «скорость ветра»: 11, «максимальная скорость ветра»: 21, «направление ветра»: 160, «давление»: 1004,2, «состояние»: 4}, {«время»: «2019-11-27 00: 00:00 ', ....

import requests
import db_mac
from collections import defaultdict
import datetime
import time
t = time.time()

station = [10382,"DE","Berlin / Tegel",52.5667,13.3167,37,"EDDT",10382,"TXL","Europe/Berlin"]

dates = [("2019-11-20","2019-11-22"), ("2019-11-27","2019-12-02") ]
insert_dict = defaultdict(tuple)

hist_weather_list = []

for d in dates:
    end = d[1]
    start = d[0]
    print(start, end)
    url = "https://api.meteostat.net/v1/history/hourly?station={station}&start={start}&end={end}&time_zone={timezone}&&time_format=Y-m-d%20H:i&key=<APIKEY>".format(station=station[0], start=start, end=end, timezone=station[-1])

    response = requests.get(url)
    weather = response.json()
    print(weather)
    for i in weather["data"]:
        hist_weather_list.append(i)

sql = "select timestamp from dump order by timestamp asc"
result = db_mac.execute(sql)

hours, rem = divmod(time.time() - t, 3600)
minutes, seconds = divmod(rem, 60)
print("step1 {:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds))

for row in result:
    try:
        ts_dump = datetime.datetime.timestamp(row[0])
        for i, hour in enumerate(hist_weather_list):
            ts1 = datetime.datetime.timestamp(datetime.datetime.strptime(hour["time"], '%Y-%m-%d %H:%M:%S'))

            ts2 = datetime.datetime.timestamp(datetime.datetime.strptime(hist_weather_list[i + 1]["time"], '%Y-%m-%d %H:%M:%S'))

            if ts1 <= ts_dump and ts_dump < ts2:

                insert_dict[row[0]] = (hour["temperature"], hour["pressure"])

    except Exception as e:
        pass



hours, rem = divmod(time.time() - t, 3600)
minutes, seconds = divmod(rem, 60)
print("step2 {:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds))


for key, value in insert_dict.items():
    sql2 = """UPDATE dump SET temperature = """ + str(value[0]) + """, pressure = """+ str(value[1]) + """ WHERE timestamp = '"""+ str(key) + """';"""
    db_mac.execute(sql2)


hours, rem = divmod(time.time() - t, 3600)
minutes, seconds = divmod(rem, 60)
print("step3 {:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds))

ОБНОВЛЕНИЕ код для многопроцессорной обработки. Я позволю ему работать ночью и дам обновление времени работы.

import requests
import db_mac
from collections import defaultdict
import datetime
import time
import multiprocessing as mp
t = time.time()



station = [10382,"DE","Berlin / Tegel",52.5667,13.3167,37,"EDDT",10382,"TXL","Europe/Berlin"]

dates = [("2019-11-20","2019-11-22"), ("2019-11-27","2019-12-02") ]
insert_dict = defaultdict(tuple)

hist_weather_list = []

for d in dates:
    end = d[1]
    start = d[0]
    print(start, end)
    url = "https://api.meteostat.net/v1/history/hourly?station={station}&start={start}&end={end}&time_zone={timezone}&&time_format=Y-m-d%20H:i&key=wzwi2YR5".format(station=station[0], start=start, end=end, timezone=station[-1])

    response = requests.get(url)
    weather = response.json()
    print(weather)
    for i in weather["data"]:
        hist_weather_list.append(i)

sql = "select timestamp from dump order by timestamp asc"
result = db_mac.execute(sql)

hours, rem = divmod(time.time() - t, 3600)
minutes, seconds = divmod(rem, 60)
print("step1 {:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds))


def find_parameters(x):

    for row in result[x[0]:x[1]]:
        try:
            ts_dump = datetime.datetime.timestamp(row[0])
            for i, hour in enumerate(hist_weather_list):
                ts1 = datetime.datetime.timestamp(datetime.datetime.strptime(hour["time"], '%Y-%m-%d %H:%M:%S'))

                ts2 = datetime.datetime.timestamp(datetime.datetime.strptime(hist_weather_list[i + 1]["time"], '%Y-%m-%d %H:%M:%S'))

                if ts1 <= ts_dump and ts_dump < ts2:

                    insert_dict[row[0]] = (hour["temperature"], hour["pressure"])

        except Exception as e:
            pass

step1 = int(len(result) /4)
step2 = 2 * step1
step3 = 3 * step1
step4 = len(result)
steps = [[0,step1],[step1,step2],[step2,step3], [step3,step4]]


pool = mp.Pool(mp.cpu_count())
pool.map(find_parameters, steps)

hours, rem = divmod(time.time() - t, 3600)
minutes, seconds = divmod(rem, 60)
print("step2 {:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds))


for key, value in insert_dict.items():
    sql2 = """UPDATE dump SET temperature = """ + str(value[0]) + """, pressure = """+ str(value[1]) + """ WHERE timestamp = '"""+ str(key) + """';"""
    db_mac.execute(sql2)


hours, rem = divmod(time.time() - t, 3600)
minutes, seconds = divmod(rem, 60)
print("step3 {:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds))

ОБНОВЛЕНИЕ 2 Он закончил и работал в течение 2:45 часов в 4 ядрах на малиновом пи , Хотя есть ли более эффективный способ сделать такие вещи?

1 Ответ

0 голосов
/ 14 февраля 2020

Итак, есть несколько мелких вещей, которые я могу придумать, чтобы немного ускорить это. Я считаю, что что-то немного помогает, особенно если вам нужно обработать много строк. Для начала, операторы print могут сильно замедлить ваш код. Я бы избавился от них, если они не нужны.

Самое главное, вы вызываете API в каждой итерации l oop. Ожидание ответа от API, вероятно, занимает большую часть вашего времени. Я посмотрел немного на API, который вы используете, но не знаю точный случай, для которого вы его используете, или как выглядят ваши даты «начало» и «конец», но если бы вы могли сделать это за меньшее количество вызовов, это было бы конечно, ускорить это l oop на много. Еще один способ сделать это, похоже, что API имеет CSV-версию данных, которые вы можете загрузить и использовать. Выполнение этого на локальных данных будет намного быстрее. Если вы выберете go этот маршрут, я бы предложил использовать pandas. (Извините, если вы уже знаете pandas, и я перебираю объяснения). Вы можете использовать: df = pd.read_csv ("filename.csv") и легко отредактировать таблицу оттуда. Вы также можете сделать df.to_ sql (params) для записи в вашу базу данных. Дайте мне знать, если вам нужна помощь в создании pandas версии этого кода.

Кроме того, по вашему коду не уверен, что это приведет к ошибке, но я бы попробовал вместо вашей для l oop (для меня в погоде ["данные"]). hist_weather_list + = погода ["данные"] или, возможно, hist_weather_list + = [погода ["данные"]

Дайте мне знать, как это происходит!

...