2016-09-08 3 views
4

이상한 발견을했을 때 Python의 asyncio을 사용하여 수면 정렬 (https://rosettacode.org/wiki/Sorting_algorithms/Sleep_sort)을 구현하기로 결정했습니다. 음수 값으로 작동하고 즉시 0을 반환합니다! 여기 asyncio.sleep은 어떻게 음수 값으로 작동합니까?

코드입니다 (여기 https://repl.it/DYTZ 실행할 수 있습니다) :

import asyncio 
import random 

async def sleepy(value): 
    return await asyncio.sleep(value, result=value) 


async def main(input_values): 
    result = [] 
    for sleeper in asyncio.as_completed(map(sleepy, input_values)): 
     result.append(await sleeper) 
    print(result) 


if __name__ == '__main__': 
    loop = asyncio.get_event_loop() 
    input_values = list(range(-5, 6)) 
    random.shuffle(input_values) 
    loop.run_until_complete(main(input_values)) 

코드는 예상대로 실행하는 데 5 초 정도 걸리지 만, 결과는 항상 [0, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5]입니다. 나는 즉시 반환하는 0을 이해할 수 있지만, 어떻게 음수 값이 올바른 순서로 되돌아 오는가?

+0

[heapq] (https://docs.python.org/3.5/library/heapq.html)는 예정 시간을 사용하여 콜백을 정렬하는 데 사용됩니다. 즉, 수면 정렬은 실제로 [heapsort] (https : //en.wikipedia.org/wiki/Heapsort) – Vincent

+0

고마워, 잘 알고있다. – user1475412

답변

3

음 :

  • delay == 0이 특수 맡았다 즉시 반환하는 것입니다, 그것은 심지어 잠을 시도하지 않습니다.
  • 0이 아닌 지연 호출 events.get_event_loop(). events.set_event_loop_policy(policy)에 대한 호출이 asyncio.tasks에 없으므로 이미 다른 곳에 설정되어 있지 않으면 기본값으로 되돌아가는 것처럼 보일 것입니다. the default is asyncio.DefaultEventLoopPolicy.
  • 에 정의되어 있지 않습니다. Windows에서 UNIX과 다릅니다. 어느 쪽이든, sleeploop.create_future()입니다. 이는 약간의 상속을 다시 정의한 것입니다. base_events.BaseEventLoop. 이것은 단지 Future() 생성자에 대한 간단한 호출이며 중요한 로직은 없습니다. 다시 루프 Future이 대표의 인스턴스에서
  • 는 다음과 같이

    future._loop.call_later(delay, 
             futures._set_result_unless_cancelled, 
             future, result) 
    
  • 하나 즉, 직접 delay 수를 처리하지 않습니다 여전히 BaseEventLoop도, 그리고 : 그것은을 추가 self.call_at를 호출 현재 시간을 지연시킵니다.
  • call_at 일정을 반환하고 events.TimerHandle을 반환하고 콜백은 Future에게 완료되었음을 알리는 것입니다. 반환 값은 작업을 취소해야하는 경우에만 관련이 있으며 작업이 정리 끝에 자동으로 수행됩니다. 스케줄링은 중요한 비트입니다.
  • _scheduledheapq을 통해 정렬됩니다. 모든 것이 정렬 된 순서대로 진행되고 타이머는 _when으로 정렬됩니다. 이것이 핵심입니다.
  • 점검 할 때마다 취소 된 예약 된 모든 항목을 제거한 다음 나머지 예약 된 콜백을 순서대로 실행하여 준비되지 않은 콜백을 실행합니다.

TL; DR :

음의 지속 시간 일정 작업에 asyncio와 잠자는 과거에 "준비"가 될 수 있습니다. 즉, 예약 된 작업 목록의 맨 위로 이동하고 이벤트 루프가 확인되는 즉시 실행됩니다. 실제로 0은 스케줄도 없기 때문에 0이 먼저 오지만, 나머지는 "늦게 실행 중"으로 스케줄러에 등록되고 늦게 순서대로 즉시 처리됩니다.

+0

와우, 이건 정말 상세합니다. 소스를 파고 들어 주셔서 감사합니다. – user1475412

4

asyncio 소스를 살펴보면 sleepspecial cases 0이 즉시 반환됩니다.

if delay == 0: 
    yield 
    return result 

당신이 소스를 통해 계속 경우 다른 값이 이벤트 루프의 call_later 방법을 통해 전달되는 것을 볼 수 있습니다. call_later이 기본 루프 (BaseEventLoop)로 구현 된 방법을 보면 call_laterpasses a time to call_at이 표시됩니다.

self.call_at(self.time() + delay, callback, *args) 

값이 순서대로 설정되는 이유는 음의 지연으로 생성 된 시간이 양의 지연이있는 생성 전에 발생하기 때문입니다. source보고

+0

나는 본다! 어쩌면 나는 모든 값을 음수로 만들어야한다. – user1475412

+0

가 - 너무 긴 추적 소스를 가져다 써서 모두 다 써 버리면 나에게 이길 수있다. –

+0

그래,하지만 너는 힙까지 줄곧 나갔다. – dirn