Python - 在多线程中使用随机数

Posted

技术标签:

【中文标题】Python - 在多线程中使用随机数【英文标题】:Python - Using nonces with multithreading 【发布时间】:2016-05-13 00:39:22 【问题描述】:

我正在使用带有请求的 python 2。这个问题更多的是对我如何提高这种性能的好奇。

现在的问题是我必须将请求标头中的加密签名发送到 HTTPS 服务器。这个签名包括一个“nonce”,它必须是一个时间戳,并且总是必须增加(在服务器端)。

显然,这会对在多个线程上运行多个 HTTP 会话造成严重破坏。请求最终没有按顺序发送,因为它们在生成标头和发送 HTTPS POST 请求之间被中断。

解决方案是在创建签名之前锁定线程,直到接收 HTTPS 数据结束。理想情况下,我想在发送 HTTP 请求后释放 LOCK,而不必等待接收数据。在发送 HTTP 标头之后,有什么方法可以使用请求释放锁?见代码示例:

self.lock 是一个 Threading.Lock。这个类(self)的这个实例在多个线程之间共享。

def get_nonce(self):
    return int(1000*time.time())

def do_post_request(self, endpoint, parameters):
    with self.lock:
        url = self.base + endpoint
        urlpath = endpoint
        parameters['nonce'] = self.get_nonce()
        postdata = urllib.urlencode(parameters)
        message = urlpath + hashlib.sha256(str(parameters['nonce']) + postdata).digest()
        signature = hmac.new(base64.b64decode(self.secret_key), message, hashlib.sha512)
        headers = 
            'API-Key': self.api_key,
            'API-Sign': base64.b64encode(signature.digest())
        
        data = urllib.urlencode(parameters)
        response = requests.post(url, data=data, headers=headers, verify=True).json()

    return response

【问题讨论】:

你能切换到grequests 或者this吗? 是的,futures 看起来最有前途,因为它看起来很轻,并且示例有 2 个代码点(开始请求和完成请求)。除非必须,否则我不想向项目添加更多依赖项。也希望未来将与 python 2.7 反向移植一起使用。 意识到这些并不能解决问题。我必须确保在释放锁之前已经发送了标头...到目前为止,为了破解它,我已经人为延迟了 500 毫秒。 :-(。唯一想到的其他建议:使用请求来准备请求数据,但使用普通套接字来实际发送数据/接收响应。我 认为 i> 你也可以使用请求来解析响应,但是,你会丢失看起来会话和重定向被自动处理的东西。你可以在服务器端进行设计更改吗? 不需要会话或重定向,所以我可能会深入研究请求对象,看看是否能找到有用的东西。猴子补丁插座什么的。 【参考方案1】:

这听起来像请求库doesn't have any support 用于异步发送。

使用默认传输适配器,Requests 不提供任何类型的非阻塞 IO。 Response.content 属性将被阻塞,直到整个响应被下载。如果您需要更多粒度,库的流式传输功能(请参阅流式处理请求)允许您一次检索更少量的响应。但是,这些调用仍然会阻塞。

如果您担心阻塞 IO 的使用,有很多项目将请求与 Python 的异步框架之一结合起来。两个很好的例子是 grequests 和 requests-futures。

我在评论中看到您对添加更多依赖项犹豫不决,所以我唯一的建议是:

当您的 nonce 被拒绝时添加重试逻辑。这似乎是最 Pythonic 的解决方案,只要 nonce 不经常被拒绝就应该可以正常工作。 限制随机数生成器。保留上一个 nonce 使用的时间戳,如果请求下一个 nonce 时时间不够长,则休眠。 批处理消息。如果协议允许,当您添加延迟以等待其他消息并将它们作为批处理发送时,您可能会发现吞吐量实际上会上升。 更改服务器,使 nonce 值不必增加。如果您控制服务器,则使消息彼此独立将为您提供更灵活的协议。 使用会话池。我猜nonce值只需要在一个会话中增加。如果您创建一个线程池并让每个线程打开自己的会话,您仍然可以获得合理的吞吐量,而不会出现您目前遇到的时间问题。

显然,您必须衡量进行这些更改的性能结果。

即使您决定添加一个依赖项,让您在发送标头后释放锁定,您仍然可能会发现偶尔会遇到时间问题。带有标头的消息包在到达服务器的途中可能会延迟。

【讨论】:

我认为摘录不恰当。我在单个线程中使用请求,因此它们确实异步运行。我正在有效地寻找可以挂钩的 on_progress_downloaded 事件(例如下载进度条功能)。到目前为止似乎是功能请求。 如果您想知道何时收到响应的开始,@beiller,请查看摘录中提到的流式传输功能。这意味着您仍然必须等待响应开始,然后才能释放锁定。如果会话池可以工作,我认为这可能是最好的选择。 嗨,唐,感谢您的回答。但是,由于各种原因,您的所有要点都不起作用。会话池将不起作用,因为 nonce 值必须在所有会话中增加。不能换服务器。批处理类似于我的锁定方法。随机数生成器是可重入的,因此无法正常工作。重试可能会奏效,但如果错误的随机数太多,我会被临时禁止。 再次感谢您的回答,基本上请求不会支持我想说的。我承认它有点专业。所以从技术上讲你是对的!

以上是关于Python - 在多线程中使用随机数的主要内容,如果未能解决你的问题,请参考以下文章

在多线程系统中使用静态对象

随机类线程安全吗?

常用类---随机数Radom

多线程中boost asio中的随机EOF

未知标签类型:在多类分类问题上使用随机森林分类器时“连续”

Sql Compact 随机产生 AccessViolationException