Уведомления

Группа в Telegram: @pythonsu

#1 Апрель 9, 2014 14:59:32

snakeand1
Зарегистрирован: 2013-10-06
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

.read() - низкая скорость, threads

Привет всем!
Есть код, в котором происходит запрос к Steam API. Запрос - urllib.request.urlopen(url). Запрос занимает около половины секунды, что меня устраивает. Меня не устраивает .read(), который занимает около 2 секунд. Из-за большого кол-ва запроса 2 секунды могут перерасти в минуты. Как можно его ускорить?
Может я не прав, но по-моему единственный шанс ускорить код - использовать потоки. И если я прав как это сделать? Пробовал запускать в двух потоках, одну и ту же функцию(включает в себя вызов других функций), потоки шли друг за другом, а не одновременно.

Офлайн

#2 Апрель 9, 2014 23:51:56

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

.read() - низкая скорость, threads

я что то не могу понять о чем речь идет. это какая библиотека urllib, где есть request? Да и лучше сразу бы код показать. А то как то 2 секунды на read() это выглядит странно, если понимать этот метод как и в случае стандартной urllib



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#3 Апрель 10, 2014 14:12:58

snakeand1
Зарегистрирован: 2013-10-06
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

.read() - низкая скорость, threads

import urllib.request
import time
import sqlite3
import json
token = ''
#Должен быть токен от стима
def check_id64(str, name):
    req = 'http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=%s&steamids=%s' % (token, str)
    req = urllib.request.urlopen(req).read().decode('utf-8')
    if name in req:
        return True
    else:
        return False
def parse():
#    gamers = str(input())
    gamers = 'Member[0] id = [U:1:103130828] name = !Butthurtus Maximus'.split('\n')
    ids = []
    nicks = []
    for x in range(len(gamers)):
        id = gamers[x].split(':')[2].split(']')[0]
        nick = gamers[x].split('=')[2][1:]
        ids.append(id)
        nicks.append(nick)
    return ids, nicks
def get_id64(id, nick):
    key = 76561197960265728
    id64s = []
    for x in range(len(id)):
        id64 = int(id[x]) + key
        result = check_id64(str(id64), nick[x])
        if result:
            id64s.append(id64)
        else:
            id64 = id64 + 1
            id64s.append(id64)
    return id64s
def get_backpack(id):
    req = 'http://api.steampowered.com/IEconItems_570/GetPlayerItems/v0001/?key=%s&steamid=%s' % (token, str(id[0]))
    request = urllib.request.urlopen(req).read() #Тот самый read
    request = request.decode()
    json_item = json.loads(request)['result']['items']
    player_items = []
    for elem in json_item:
        defindex = elem['defindex']
        if defindex not in player_items:
            player_items.append(defindex)
    return player_items
def find(defind):
    t = (defind, )
    conn = sqlite3.connect('dota2items.db')
    c = conn.cursor()
    c.execute('select * from items where defindex=?', t)
    return c
def get_items(sorted_items):
    items_ready = []
    for elem in sorted_items:
        item = find(str(elem)).fetchone()
        items_ready.append(item)
    return items_ready
def main():
    data = parse()
    id = data[0]
    nickname = data[1]
    id64 = get_id64(id, nickname)
    items = get_items(get_backpack(id64))
if __name__ == '__main__':
    a = time.time()
    main()
    print(time.time() - a)

python 3.3.2

Отредактировано snakeand1 (Апрель 10, 2014 14:22:58)

Офлайн

#4 Апрель 11, 2014 21:21:31

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

.read() - низкая скорость, threads

JOHN_16
я что то не могу понять о чем речь идет. это какая библиотека urllib, где есть request?
это не requests
в третьем питоне urllib и urllib2 собрали в один пакет, упорядочив его

snakeand1
Меня не устраивает .read(), который занимает около 2 секунд. Из-за большого кол-ва запроса 2 секунды могут перерасти в минуты. Как можно его ускорить?
вообще, можно не через .read() читать, а через next()

>>> import urllib.request
>>> data = urllib.request.urlopen('http://python.su')
>>> next(data)
b'\n'
>>> next(data)
b'\n'
>>> next(data)
b'\n'
>>> next(data)
b'\n'
>>> next(data)
b'\n'
>>> next(data)
b'<!doctype html>\n'
>>>
>>> 
>>> for i, _ in zip(data, range(3)):
...   i
... 
b'<!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ -->\n'
b'<!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]-->\n'
b'<!--[if IE 7 ]>    <html lang="en" class="no-js ie7"> <![endif]-->\n'
>>>

snakeand1
Может я не прав, но по-моему единственный шанс ускорить код - использовать потоки.
если запросов много, то лучше распределить их, чтобы они параллельно работали

snakeand1
Пробовал запускать в двух потоках, одну и ту же функцию(включает в себя вызов других функций), потоки шли друг за другом, а не одновременно.
непонятно, как ты запускал и как диагностировал

можно построчно читать через next() (явно или в цикле) и помещать строки в очередь (queue.Queue), а там уже другим потоком из очереди распределять

но всё это в одном случае: если распараллеливание необходимо



Офлайн

#5 Апрель 12, 2014 08:07:27

snakeand1
Зарегистрирован: 2013-10-06
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

.read() - низкая скорость, threads

Запускал я потоки, скорее всего, неправильно

t1 = threading.Thread(target=main, args=(0, ))
t2 = threading.Thread(target=main, args=(1, ))
t1.start()
t2.start()
t1.join(); t2.join()
Аргументы для запусков потоков - это задержка. Делал через time.sleep()
В итоге время было в два раза больше, чем когда я запускал функцию main()

Офлайн

#6 Апрель 12, 2014 09:58:11

snakeand1
Зарегистрирован: 2013-10-06
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

.read() - низкая скорость, threads

Попытался написать потокобезопасный код(заменил все списки на очереди)

def get_id64(id, nick):
    key = 76561197960265728
    for x in range(len(id)):
        id64 = int(id[x]) + key
        result = check_id64(str(id64), nick[x])
        if result:
            info = id64, nick[x]
            gamer_queue.put(info)
        else:
            id64 += 1
            info = id64, nick[x]
            gamer_queue.put(info)
В итоге gamer_queue.put() срабатывает только один раз, будто написан вне цикла.
Такая же проблема в другой функции.
В чем может быть проблема?

Все получилось!

Отредактировано snakeand1 (Апрель 12, 2014 10:28:56)

Офлайн

#7 Апрель 12, 2014 10:49:27

snakeand1
Зарегистрирован: 2013-10-06
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

.read() - низкая скорость, threads

Вообщем все сделал - потоки работают, но работают они через одно место.
Код

a = time.time()
    find_info()
    thread1 = threading.Thread(target=main)
    thread2 = threading.Thread(target=main)
    thread1.start()
    thread2.start()
    print(time.time() - a)

Вывод консоли
http://api.steampowered.com/IEconItems_570/GetPlayerItems/v0001/?key=&steamid=76561198063396556
http://api.steampowered.com/IEconItems_570/GetPlayerItems/v0001/?key=&steamid=76561198075819059
3.1671149730682373
http://api.steampowered.com/IEconItems_570/GetPlayerItems/v0001/?key=&steamid=76561198043509835
http://api.steampowered.com/IEconItems_570/GetPlayerItems/v0001/?key=&steamid=76561198079601121
http://api.steampowered.com/IEconItems_570/GetPlayerItems/v0001/?key=&steamid=76561197980940780
http://api.steampowered.com/IEconItems_570/GetPlayerItems/v0001/?key=&steamid=76561198070399982
Process finished with exit code 0

Отредактировано snakeand1 (Апрель 12, 2014 10:49:49)

Офлайн

#8 Апрель 12, 2014 11:40:57

snakeand1
Зарегистрирован: 2013-10-06
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

.read() - низкая скорость, threads

Все сделал! Чтобы все выполнялось по-порядку, надо было написать thread1.join()
thread2.join().
Тему можно закрывать!

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version