Asynchronous Requests with Python requests Asynchronous Requests with Python requests python python

Asynchronous Requests with Python requests


Note

The below answer is not applicable to requests v0.13.0+. The asynchronous functionality was moved to grequests after this question was written. However, you could just replace requests with grequests below and it should work.

I've left this answer as is to reflect the original question which was about using requests < v0.13.0.


To do multiple tasks with async.map asynchronously you have to:

  1. Define a function for what you want to do with each object (your task)
  2. Add that function as an event hook in your request
  3. Call async.map on a list of all the requests / actions

Example:

from requests import async# If using requests > v0.13.0, use# from grequests import asyncurls = [    'http://python-requests.org',    'http://httpbin.org',    'http://python-guide.org',    'http://kennethreitz.com']# A simple task to do to each response objectdef do_something(response):    print response.url# A list to hold our things to do via asyncasync_list = []for u in urls:    # The "hooks = {..." part is where you define what you want to do    #     # Note the lack of parentheses following do_something, this is    # because the response will be used as the first argument automatically    action_item = async.get(u, hooks = {'response' : do_something})    # Add the task to our list of things to do via async    async_list.append(action_item)# Do our list of things to do via asyncasync.map(async_list)


async is now an independent module : grequests.

See here : https://github.com/kennethreitz/grequests

And there: Ideal method for sending multiple HTTP requests over Python?

installation:

$ pip install grequests

usage:

build a stack:

import grequestsurls = [    'http://www.heroku.com',    'http://tablib.org',    'http://httpbin.org',    'http://python-requests.org',    'http://kennethreitz.com']rs = (grequests.get(u) for u in urls)

send the stack

grequests.map(rs)

result looks like

[<Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>]

grequests don't seem to set a limitation for concurrent requests, ie when multiple requests are sent to the same server.


I tested both requests-futures and grequests. Grequests is faster but brings monkey patching and additional problems with dependencies. requests-futures is several times slower than grequests. I decided to write my own and simply wrapped requests into ThreadPoolExecutor and it was almost as fast as grequests, but without external dependencies.

import requestsimport concurrent.futuresdef get_urls():    return ["url1","url2"]def load_url(url, timeout):    return requests.get(url, timeout = timeout)with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:    future_to_url = {executor.submit(load_url, url, 10): url for url in     get_urls()}    for future in concurrent.futures.as_completed(future_to_url):        url = future_to_url[future]        try:            data = future.result()        except Exception as exc:            resp_err = resp_err + 1        else:            resp_ok = resp_ok + 1