Увеличение количества запросов в секунду - PullRequest
0 голосов
/ 31 октября 2018

Я пытаюсь увеличить количество запросов в секунду. В настоящее время я качаю Python 2.7 и могу получать примерно 1 запрос в секунду. Нужно ли многопоточное / многопроцессорное выполнение функции или асинхронный запуск нескольких экземпляров функции. Я понятия не имею, как заставить это работать. Пожалуйста, помогите: -)

while True:
    r = requests.post(url, allow_redirects=False, data={
        str(formDataNameLogin): username,
        str(formDataNamePass): password,
    })

    print 'Sending username: %s with password %s' % (username, password)

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Вы можете сделать несколько параллельных запросов, используя многопоточность:

import Queue
import threading
import time
import requests

exit_flag = 0

class RequestThread(threading.Thread):
    def __init__(self, thread_id, name, q):
        threading.Thread.__init__(self)
        self.thread_id = thread_id
        self.name = name
        self.q = q
    def run(self):
        print("Starting {0:s}".format(self.name))
        process_data(self.name, self.q)
        print("Exiting {0:s}".format(self.name))

def process_data(thread_name, q):
    while not exit_flag:
        queue_lock.acquire()
        if not qork_queue.empty():
            data = q.get()
            queue_lock.release()
            print("{0:s} processing {1:s}".format(thread_name, data))
            response = requests.get(data)
            print(response)
        else:
            queue_lock.release()
        time.sleep(1)

thread_list = ["Thread-1", "Thread-2", "Thread-3"]
request_list = [
    "https://api.github.com/events",
    "http://api.plos.org/search?q=title:THREAD",
    "http://api.plos.org/search?q=title:DNA",
    "http://api.plos.org/search?q=title:PYTHON",
    "http://api.plos.org/search?q=title:JAVA"
]
queue_lock = threading.Lock()
qork_queue = Queue.Queue(10)
threads = []
thread_id = 1

# Create new threads
for t_name in thread_list:
    thread = RequestThread(thread_id, t_name, qork_queue)
    thread.start()
    threads.append(thread)
    thread_id += 1

# Fill the queue
queue_lock.acquire()
for word in request_list:
    qork_queue.put(word)
queue_lock.release()

# Wait for queue to empty
while not qork_queue.empty():
    pass

# Notify threads it's time to exit
exit_flag = 1

# Wait for all threads to complete
for t in threads:
    t.join()

print("Exiting Main Thread")

Выход:

Starting Thread-1
Starting Thread-2
Starting Thread-3
Thread-1 processing https://api.github.com/events
Thread-2 processing http://api.plos.org/search?q=title:THREAD
Thread-3 processing http://api.plos.org/search?q=title:DNA
<Response [200]>
<Response [200]>
<Response [200]>
Thread-2 processing http://api.plos.org/search?q=title:PYTHON
Thread-3 processing http://api.plos.org/search?q=title:JAVA
Exiting Thread-1
<Response [200]>
<Response [200]>
Exiting Thread-3
Exiting Thread-2
Exiting Main Thread

Небольшое объяснение, хотя я не эксперт по многопоточности:

1.Queue

Модуль Queue позволяет вам создать новый объект очереди, который может содержать определенное количество элементов. Существуют следующие методы управления очередью:

  • get () - удаляет и возвращает элемент из очереди.
  • put () - добавляет элемент в очередь. qsize () - возвращает количество элементов, которые в данный момент находятся в очереди.
  • empty () - возвращает True, если очередь пуста; в противном случае Ложь.
  • full () - возвращает True, если очередь заполнена; в противном случае Ложь.

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

2.Lock

Модуль потоков, поставляемый с Python, включает в себя простой в реализации механизм блокировки , который позволяет синхронизировать потоки. Новая блокировка создается путем вызова метода Lock(), который возвращает новую блокировку.

Примитивная блокировка находится в одном из двух состояний: «заблокирована» или «разблокирована». Это создается в разблокированном состоянии. У него есть два основных метода acqu () и отпустить (). Когда состояние разблокировано, acqu () изменяет состояние заблокирован и немедленно возвращается. Когда состояние заблокировано, приобретать () блокирует, пока вызов release () в другом потоке не изменит его на разблокированный, затем вызов acqu () сбрасывает его в заблокированный и возвращает. Метод release () должен вызываться только в заблокированном состоянии; меняется состояние разблокируется и возвращается немедленно. Если сделана попытка чтобы снять разблокированную блокировку, будет вызвано ThreadError.

Для более человеческих языковых блокировок наиболее фундаментальным механизмом синхронизации является модуль потоков. В любое время блокировка может удерживаться одним потоком или никаким потоком вообще. Если поток пытается удержать блокировку, которая уже удержана каким-либо другим потоком, выполнение первого потока останавливается до тех пор, пока блокировка не будет снята.

Блокировки обычно используются для синхронизации доступа к общему ресурсу. Для каждого общего ресурса создайте объект Lock. Когда вам нужно получить доступ к ресурсу, вызовите acqu для удержания блокировки (это будет ждать освобождения блокировки, если это необходимо) и вызовите освобождение для ее снятия.

3.Thread

Чтобы реализовать новый поток с помощью модуля потоков, вам нужно сделать следующее:

  • Определить новый подкласс класса Thread.
  • Переопределите метод init (self [, args]), чтобы добавить дополнительные аргументы.
  • Затем переопределите метод run (self [, args]), чтобы реализовать то, что должен делать поток при запуске.

Как только вы создали новый подкласс Thread, вы можете создать его экземпляр, а затем запустить новый поток, вызвав start (), который, в свою очередь, вызывает метод run (). Методы:

  • run () - метод является точкой входа для потока.
  • start () - метод запускает поток, вызывая метод run.
  • join ([время]) - ожидает завершения потоков.
  • isAlive () - метод проверяет, выполняется ли еще поток.
  • getName () - возвращает имя потока.
  • setName () - устанавливает имя потока.

Это действительно быстрее?

Использование одного потока:

$ time python single.py 
Processing request url: https://api.github.com/events
<Response [200]>
Processing request url: http://api.plos.org/search?q=title:THREAD
<Response [200]>
Processing request url: http://api.plos.org/search?q=title:DNA
<Response [200]>
Processing request url: http://api.plos.org/search?q=title:PYTHON
<Response [200]>
Processing request url: http://api.plos.org/search?q=title:JAVA
<Response [200]>
Exiting Main Thread

real    0m22.310s
user    0m0.096s
sys 0m0.022s

Использование 3 потоков:

Starting Thread-1
Starting Thread-2
Starting Thread-3
Thread-3 processing https://api.github.com/events
Thread-1 processing http://api.plos.org/search?q=title:THREAD
Thread-2 processing http://api.plos.org/search?q=title:DNA
<Response [200]>
<Response [200]>
<Response [200]>
Thread-1 processing http://api.plos.org/search?q=title:PYTHON
Thread-2 processing http://api.plos.org/search?q=title:JAVA
Exiting Thread-3
<Response [200]>
<Response [200]>
Exiting Thread-1
 Exiting Thread-2
Exiting Main Thread

real    0m11.726s
user    0m6.692s
sys 0m0.028s

Использование 5 потоков:

time python multi.py 
Starting Thread-1
Starting Thread-2
Starting Thread-3
 Starting Thread-4
Starting Thread-5
Thread-5 processing https://api.github.com/events
Thread-1 processing http://api.plos.org/search?q=title:THREAD
Thread-2 processing http://api.plos.org/search?q=title:DNA
Thread-3 processing http://api.plos.org/search?q=title:PYTHONThread-4 processing http://api.plos.org/search?q=title:JAVA

<Response [200]>
<Response [200]>
 <Response [200]>
<Response [200]>
<Response [200]>
Exiting Thread-5
Exiting Thread-4
Exiting Thread-2
Exiting Thread-3
Exiting Thread-1
Exiting Main Thread

real    0m6.446s
user    0m1.104s
sys 0m0.029s

Почти в 4 раза быстрее для 5 потоков. И это всего лишь 5 пустышек. Вообразите для большей части данных.

Пожалуйста, обратите внимание: у меня есть только одинМы протестировали его под python 2.7. Для python 3.x, вероятно, необходимы незначительные корректировки.

0 голосов
/ 31 октября 2018

Просто используйте любую асинхронную библиотеку. Я думаю, что асинхронные варианты запросов, такие как grequest , txrequests, Request-Futures и Request-Threads, будут работать лучше для вас. Ниже приведен пример кода из файла readme для grequests:

import grequests

urls = [
    'http://www.heroku.com',
    'http://python-tablib.org',
    'http://httpbin.org',
    'http://python-requests.org',
    'http://fakedomain/',
    'http://kennethreitz.com'
]

Создать набор неотправленных запросов:

rs = (grequests.get(u) for u in urls)

Отправьте их все одновременно:

grequests.map(rs)

Использование или изучение других упомянутых модулей, например, request-threads, может быть немного более сложным, особенно с python 2

from twisted.internet.defer import inlineCallbacks
from twisted.internet.task import react
from requests_threads import AsyncSession

session = AsyncSession(n=100)

@inlineCallbacks
def main(reactor):
    responses = []
    for i in range(100):
        responses.append(session.get('http://httpbin.org/get'))

    for response in responses:
        r = yield response
        print(r)

if __name__ == '__main__':
    react(main)

asyncio и aiohttp могут быть еще более примечательными, но, я думаю, было бы проще узнать версию уже знакомого модуля.

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

...