Python 同时发送HTTP请求

Python 同时发送HTTP请求,python,python-requests,python-multithreading,Python,Python Requests,Python Multithreading,我希望向API端点发送100K-300K POST请求——这些请求来自我正在迭代的JSON对象列表。不幸的是,我能使用的最大块大小是一次10个事件,这大大降低了发送我想要的所有事件的速度。定义JSON对象列表后: chunkSize= 10 for i in xrange(0, len(list_of_JSON), chunkSize): chunk = list_of_JSON[i:i+chunkSize] #10 endpoint = "" d_profile = "

我希望向API端点发送100K-300K POST请求——这些请求来自我正在迭代的JSON对象列表。不幸的是,我能使用的最大块大小是一次10个事件,这大大降低了发送我想要的所有事件的速度。定义JSON对象列表后:

chunkSize= 10
for i in xrange(0, len(list_of_JSON), chunkSize):
    chunk = list_of_JSON[i:i+chunkSize] #10
    endpoint = ""
    d_profile = "[" + ",".join(json.dumps(x) for x in chunk) + "]"
    str_event = d_profile
    try:
         url = base_api + endpoint + "?api_key=" + api_key + "&event=" + str_event 
         r = requests.post(url)
         print r.content
         print i
    except:
        print 'failed'
这个过程非常缓慢地发送事件。我已经研究了多线程/并发/和并行处理的可能性,尽管我对这一主题完全陌生。经过一些研究,我想出了一个丑陋的笑话:

import logging
import threading
import time

logging.basicConfig(level=logging.DEBUG,
                format='[%(levelname)s] (%(threadName)-10s) %(message)s',
                )

def worker():
    logging.debug('Starting')
    import time
    chunkSize= 10
    for i in xrange(0, (len(list_of_JSON)/2), chunkSize):
        chunk = list_of_JSON[i:i+chunkSize] #10
        endpoint = ""
        d = "[" + ",".join(json.dumps(x) for x in chunk) + "]"
        str_event = d
        try:
            url = base_api + endpoint + "?api_key=" + api_key + "&event=" + str_event 
            r = requests.post(url)
            print r.content
            print i
        except:
            print 'failed'
    time.sleep(2)
    logging.debug('Exiting')

def my_service():
    logging.debug('Starting')
    import time
    chunkSize= 10
    for i in xrange(((len(list_of_JSON)/2)+1), len(list_of_JSON), chunkSize):
        chunk = list_of_JSON[i:i+chunkSize] #10
        endpoint = ""
        d = "[" + ",".join(json.dumps(x) for x in chunk) + "]"
        str_event = d
        try:
            url = base_api + endpoint + "?api_key=" + api_key + "&event=" + str_event 
            r = requests.post(url)
            print r.content
            print i
        except:
            print 'failed'
    time.sleep(3)
    logging.debug('Exiting')

t = threading.Thread(target=my_service)
w = threading.Thread(target=worker)


w.start()
t.start()
如有任何建议或重构,将不胜感激


编辑:我相信我的实现实现了我想要的。我已经看过了,但是仍然不确定这个解决方案有多好或者效率有多高

您可以使用scrapy,它按照注释中的建议使用twisted。Scrapy是一个用于抓取网页的框架,但您也可以使用它发送post请求。实现与代码相同功能的爬行器大致如下所示:

class EventUploader(scrapy.Spider):
    BASE_URL = 'http://stackoverflow.com/'  # Example url

    def start_requests(self):
        for chunk in list_of_JSON:
            get_parameters = {
                'api_key': api_key,
                'event': json.dumps(chunk),  # json.dumps can encode lists too
            }

            url = "{}/endpoint?{}".format(
                self.BASE_URL, urlencode(get_parameters))
            yield scrapy.FormRequest(url, formdata={}, callback=self.next)

    def next(self, response):
        # here you can assert everything went ok
        pass
scrapy runspider my_spider.py
一旦你的爬行器就位,你就可以使用scrapy中间件来限制你的请求。您可以这样运行上载程序:

class EventUploader(scrapy.Spider):
    BASE_URL = 'http://stackoverflow.com/'  # Example url

    def start_requests(self):
        for chunk in list_of_JSON:
            get_parameters = {
                'api_key': api_key,
                'event': json.dumps(chunk),  # json.dumps can encode lists too
            }

            url = "{}/endpoint?{}".format(
                self.BASE_URL, urlencode(get_parameters))
            yield scrapy.FormRequest(url, formdata={}, callback=self.next)

    def next(self, response):
        # here you can assert everything went ok
        pass
scrapy runspider my_spider.py

这可能是一个很老的复制品,我建议研究类似的东西。文档中有一些基本的示例可以完全满足您的要求。请查看eventlet,谢谢。实际上,该链接上的第一个答案使用了线程,这仍然是相关的。以及twisted,它提供异步请求。多处理可以在与第一个答案相同的结构中使用,而不是线程。请注意:只要请求生成遵循闭环设计,请求速率就会受到并发线程数量以及每个请求的响应时间的限制。Async可以避免这种情况,但理解它通常是非常重要的。