通过Asyncio解决阻塞httppython函数
Solve blocking http python function through Asyncio
我正在实施一个通过 http 请求进行通信的区块链 (inspired by this blogpost)。这个区块链有一个工作证明方法,根据难度,可以在相当长的一段时间内阻止其他 http 请求。这就是为什么我要尝试实现 python 的新 asyncio
功能。以下作品:
async def proof_of_work(self, last_proof):
"""
Simple Proof of Work Algorithm:
- Find a number p' such that hash(pp') contains leading 4 zeroes, where p is the previous p'
"""
proof = 0
while self.valid_proof(last_proof, proof) is False:
proof += 1
await asyncio.sleep(1)
return proof
但是,这让我的工作量证明非常慢,我猜这是因为它在每次迭代后都被迫休眠。什么是更优雅的方法来解决这个问题?
while self.valid_proof(last_proof, proof) is False:
proof += 1
if proof % 1000 == 0:
await asyncio.sleep(1)
会加快速度,但看起来有点脏。实现这个的正确方法是什么?
如果你想 运行 CPU-阻塞协程中的代码,你应该 运行 它在单独的执行流程中(以避免 asyncio 的事件循环冻结)使用 run_in_executor()
.
如果您只是想要另一个执行流程,或者(我认为更好)使用 ProcessPoolExecutor
将 CPU 相关工作委托给其他核心,您可以使用 ThreadPoolExecutor
。
import asyncio
from concurrent.futures import ProcessPoolExecutor
import hashlib
# ORIGINAL VERSION:
# https://github.com/dvf/blockchain/blob/master/blockchain.py
def valid_proof(last_proof, proof):
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000"
def proof_of_work(last_proof):
proof = 0
while valid_proof(last_proof, proof) is False:
proof += 1
return proof
# ASYNC VERSION:
async def async_proof_of_work(last_proof):
proof = await loop.run_in_executor(_executor, proof_of_work, last_proof)
return proof
async def main():
proof = await async_proof_of_work(0)
print(proof)
if __name__ == '__main__':
_executor = ProcessPoolExecutor(4)
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main())
finally:
loop.run_until_complete(loop.shutdown_asyncgens())
loop.close()
输出:
69732
我正在实施一个通过 http 请求进行通信的区块链 (inspired by this blogpost)。这个区块链有一个工作证明方法,根据难度,可以在相当长的一段时间内阻止其他 http 请求。这就是为什么我要尝试实现 python 的新 asyncio
功能。以下作品:
async def proof_of_work(self, last_proof):
"""
Simple Proof of Work Algorithm:
- Find a number p' such that hash(pp') contains leading 4 zeroes, where p is the previous p'
"""
proof = 0
while self.valid_proof(last_proof, proof) is False:
proof += 1
await asyncio.sleep(1)
return proof
但是,这让我的工作量证明非常慢,我猜这是因为它在每次迭代后都被迫休眠。什么是更优雅的方法来解决这个问题?
while self.valid_proof(last_proof, proof) is False:
proof += 1
if proof % 1000 == 0:
await asyncio.sleep(1)
会加快速度,但看起来有点脏。实现这个的正确方法是什么?
如果你想 运行 CPU-阻塞协程中的代码,你应该 运行 它在单独的执行流程中(以避免 asyncio 的事件循环冻结)使用 run_in_executor()
.
如果您只是想要另一个执行流程,或者(我认为更好)使用 ProcessPoolExecutor
将 CPU 相关工作委托给其他核心,您可以使用 ThreadPoolExecutor
。
import asyncio
from concurrent.futures import ProcessPoolExecutor
import hashlib
# ORIGINAL VERSION:
# https://github.com/dvf/blockchain/blob/master/blockchain.py
def valid_proof(last_proof, proof):
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000"
def proof_of_work(last_proof):
proof = 0
while valid_proof(last_proof, proof) is False:
proof += 1
return proof
# ASYNC VERSION:
async def async_proof_of_work(last_proof):
proof = await loop.run_in_executor(_executor, proof_of_work, last_proof)
return proof
async def main():
proof = await async_proof_of_work(0)
print(proof)
if __name__ == '__main__':
_executor = ProcessPoolExecutor(4)
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main())
finally:
loop.run_until_complete(loop.shutdown_asyncgens())
loop.close()
输出:
69732