Вы можете сделать несколько параллельных запросов, используя многопоточность:
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, вероятно, необходимы незначительные корректировки.