Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Ruby에서 비동기 스레드 테스트

스레드와 비동기 환경은 처음에는 약간 까다롭습니다. 상호 작용을 조직화할 수 있는 좋은 멘탈 모델이 없으면 문제에 빠지기 쉽고 예기치 않은 결과가 발생합니다. 게다가 적절한 도구나 테스트 패턴 없이 비동기 코드를 테스트하는 것은 어려울 수 있습니다.

스레드를 사람으로, 공유 객체를 소유할 수 있는 '사물'로 생각하면 다중 스레드 시스템의 작업을 구성하는 데 도움이 됩니다. 이 에피소드에서는 비동기 Ruby 코드 테스트에 대한 모든 것을 배우기 위한 예제를 살펴보겠습니다.

Rails 또는 Rack 또는 웹 브라우저 프론트 엔드로 비동기 환경에 있는 모든 애플리케이션을 사용하는 경우. 랙 #call 항상 비동기적으로 호출됩니다. 따라서 알고 있든 모르든 이미 다중 스레드 구성 요소를 사용하고 있을 가능성이 큽니다.

테스트:트리거, 수집 및 확인

비동기식 콜백 API 테스트는 3단계 패턴을 따라 동기식으로 만들 수 있습니다. 트리거 , 수집 , 확인 . 각 스레드가 별도의 개인으로, 또한 한 번에 한 개인만 소유할 수 있는 개체로 생각하십시오.

우리는 배트맨과 그의 7가지 다른 슈트의 예를 사용할 것입니다. 이것은 실용적인 예이고 우리는 도시를 구하려고 할 때 모든 양복이 Alfred와 함께 세탁되어 있는지 여부를 아는 것의 중요성을 이해할 수 있기 때문입니다.

예:박쥐동굴에서 빨래하는 날

예를 들어 Alfred는 배트맨의 슈트를 세탁하고 있습니다. SuitWashScheduler는 각 세탁 이벤트에 대한 콜백을 호출하는 스케줄러입니다. 스케줄러는 시작 후 1초부터 1초 간격으로 7개의 콜백을 만듭니다. 트리거는 SuitWashScheduler의 생성입니다. .

class SuitWashScheduler
  def initialize(cnt)
    Thread.new {
      cnt.times {
        sleep(1.0)
        yield
      }
    }
  end
end

수집

경쟁 조건을 피하기 위해 결과 수집은 스레드로부터 안전해야 합니다. 둘 이상의 스레드에서 공유되는 모든 개체는 보호되어야 합니다. 보호는 개체의 소유자를 추적하는 방법입니다. 소유자만 개체를 ​​변경하거나 볼 수 있습니다. 전투복은 배트맨과 함께만 사용하거나 알프레드와 함께 세탁할 수 있습니다.

우호적인 관계를 유지하기 위해 스레드(베트남 또는 알프레드 은유에서)는 짧은 시간 동안만 소유권을 가지고 있다가 소유권을 포기합니다. Mutex 일반적으로 소유자를 추적하는 데 사용됩니다. SuitwashScheduler 콜백은 카운터가 증가할 때 결과 카운터를 소유합니다. SuitWashScheduler에서 실행되는 콜백 스레드는 카운터가 대상에 도달할 때 모든 결과가 수신되었음을 알립니다.

예제 작성은 일부 전역 설정으로 시작합니다. 실제 응용 프로그램에서 전역은 클래스 또는 개체 속성으로 대체됩니다.

$main_thread = Thread.current
$mu = Mutex.new
$count = 0
$target = 7

관리자 및 소유자

$main_thread$mu $target 동안 스레드를 관리하고 테스트 완료를 기다리는 데 사용됩니다. 및 $count 테스트 결과를 추적합니다. 이것은 간단한 테스트이므로 결과를 수집하고 확인하는 것이 간단해야 합니다.

테스트는 SuitWashScheduler의 새 인스턴스를 생성하여 시작됩니다. , 초기화 프로그램에 $target 제공 반복 횟수. 이 경우 세탁이 필요한 슈트 7개. 제공된 블록은 SuitWashScheduler에서 실행됩니다. 실. 각 반복에 대해 $count 증가되어 인쇄됩니다.

앞을 내다보면 메인 테스트 스레드가 $count 또한 $count의 소유권이 필요함을 의미합니다. $count의 소유권을 가져오는 수단이기도 합니다. 필요합니다. $mu Mutex instance는 소유권 토큰입니다. SuitWashScheduler.new에 전달된 블록에서 $mu.synchronize 호출 블록은 $count를 설정하기에 충분한 시간 동안 소유권을 갖습니다. 그리고 결과를 확인합니다. 잠시 후 결과를 확인하세요.

SuitWashScheduler.new($target) {
  $mu.synchronize {
    $count += 1
    puts $count
    $main_thread.wakeup if $target <= $count
  }
}

확인:모든 수트가 끝났습니까?

메인 스레드로 돌아가서 테스트가 완료될 때까지 기다려야 합니다. 배트맨은 7개의 슈트가 모두 완성되기 전에 기다려야 합니다. 확인해야 할 두 가지 조건이 있습니다. 테스트는 $count를 업데이트합니다. 예상대로 배트맨은 테스트가 끝나 시간이 초과되기를 기다리다가 지루해집니다. $count를 확인하기 전에 $target에 도달했는지 확인 , $count의 소유권 필요합니다. SuitWashScheduler 블록에서와 같이 $mu.synchronize 호출 사용됩니다.

그러나 그것은 옳지 않습니다. 메인 스레드를 잠그면 SuitWashScheduler 스레드가 $count를 변경합니다. ? 운 좋게도 이것을 처리하는 깔끔한 트릭이 있습니다. Mutex 클래스에 #sleep이 있습니다. 소유권을 포기하고 시간이 초과되거나 깨어날 때까지 기다리는 방법입니다. 시간 초과 또는 #wakeup을 통해 깨우면 한 번 메인 스레드 $mu 호출 계속하기 전에 소유권을 다시 얻으려고 시도합니다. 소유권이 확보되면 결과를 확인하고 테스트의 통과 또는 실패 상태를 결정할 수 있습니다.

$mu.synchronize {
  $mu.sleep($target + 1)
  if $target != $count
    puts 'FAILED'
  else
    puts 'Passed! All suits are washed and clean'
  end
}

이에 대해 더 깊이 알고 싶다면 여러 스케줄러를 만들고 Mutex가 $count를 유지하는 방법을 확인하여 예제를 좀 더 흥미롭게 만들 수 있습니다. 충돌로 인한 변화. 마치 배트맨이 알프레드에게 몇 벌의 옷을 보내 세탁을 하고 다른 옷을 세탁소에 보내는 것처럼. $target 수표는 모든 예상 수익률의 합계입니다.

반올림

스레드 및 비동기 환경 작업은 올바른 정신 모델을 사용하면 더 쉬워집니다. 이 게시물에서 우리는 스레드에 대한 은유로 사람을 사용하고 한 번에 한 스레드 또는 사람만 소유할 수 있는 공유 객체에 대한 은유로 물리적 개체(슈트)를 사용했습니다. . 이렇게 추상화하면 더 쉽게 이해하고 기억할 수 있습니다.

의 예제가 비동기식 메커니즘을 기억할 수 있기를 바랍니다. 하지만 배트맨이 옷을 모두 세탁하는 동안 바닥을 드러내는 이미지가 너무 오래 남아 있지 않기를 바랍니다.

추신 블로그에서 배트맨 비유를 모두 마쳤으면 알려주세요.