2017-12-09 1 views
1

HTTP 요청 (inspired by this blogpost)을 통해 통신하는 블록 체인을 구현 중입니다. 이 블록 체인은 어려움에 따라 꽤 많은 시간 동안 다른 http 요청을 차단할 수있는 작업 증명 방법을 제공합니다. 이것이 파이썬에서 새로운 asyncio 기능을 구현하려는 이유입니다. 다음은 작동합니다 :Asyncio를 통해 http 파이썬 기능을 풀어 냄.

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) 

조금 더 빨리 할 수 ​​있지만 약간 더러워 보입니다. 이것을 구현하는 올바른 방법은 무엇입니까?

+0

실행 CPU 집약적 코드 [asyncio.run_in_excutor (https://asyncio.readthedocs.io/en/latest/threads.html) – Vincent

+0

'self.valid_proof (...)'는 블로킹 IO (HTTP 요청, ...)를 사용합니다. 그렇다면이 메서드를 "async"하고 asyncio 호환 코드를 내부에 사용해야합니다. – glenfant

+0

수면 시간을 줄일 수도 있습니다. 실제로 여기서자는 것이 필요하지 않습니다. 루프를 만들어 다른 작업에 실행할 기회를주고 싶을뿐입니다. – dirn

답변

1

coroutine에서 CPU 차단 코드를 실행하려면 run_in_executor()을 사용하여 별도의 실행 흐름 (asyncio의 이벤트 루프 고정 방지)으로 실행해야합니다.

또 다른 실행 흐름을 원할 경우 ProcessPoolExecutor을 사용하여 다른 코어에 위임 할 때을 사용할 수 있습니다.

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 
관련 문제