[C#] CancellationToken이 CancellationTokenSource와 다른 이유는 무엇입니까?

클래스 CancellationToken외에도 .NET 구조체가 도입 된 이유에 대한 근거를 찾고 CancellationTokenSource있습니다. API가 어떻게 사용되는지 이해 하지만 API가 그렇게 설계 되었는지 이해하고 싶습니다 .

즉, 왜 우리는 :

var cts = new CancellationTokenSource();
SomeCancellableOperation(cts.Token);

...
public void SomeCancellableOperation(CancellationToken token) {
    ...
    token.ThrowIfCancellationRequested();
    ...
}

다음 CancellationTokenSource과 같이 직접 전달하는 대신 :

var cts = new CancellationTokenSource();
SomeCancellableOperation(cts);

...
public void SomeCancellableOperation(CancellationTokenSource cts) {
    ...
    cts.ThrowIfCancellationRequested();
    ...
}

이는 토큰을 전달하는 것보다 취소 상태 확인이 더 자주 발생한다는 사실을 기반으로 성능 최적화입니까?

따라서 CancellationTokenSource추적 및 업데이트를 유지할 수 있으며 CancellationTokens각 토큰에 대해 취소 확인이 로컬 필드 액세스입니까?

두 가지 경우 모두 잠금이없는 휘발성 부울만으로 충분하다는 것을 감안할 때 여전히 더 빠른 이유를 알 수 없습니다.

감사!



답변

나는이 클래스들의 디자인과 구현에 관여했다.

짧은 대답은 ” 문제의 분리 “입니다. 다양한 구현 전략이 있으며 유형 시스템 및 초기 학습과 관련하여 일부가 더 간단하다는 것은 사실입니다. 그러나 CTS와 CT는 많은 시나리오 (딥 라이브러리 스택, 병렬 계산, 비동기 등)에서 사용하기위한 것으로 복잡한 사용 사례를 염두에두고 설계되었습니다. 성공적인 패턴을 장려하고 성능을 저하시키지 않으면 서 반 패턴을 방지하기위한 디자인입니다.

API가 잘못 작동하여 문이 열려 있으면 취소 설계의 유용성이 빠르게 사라질 수 있습니다.

CancellationTokenSource == “취소 트리거”및 연결된 리스너 생성

CancellationToken == “취소 청취자”


답변

나는 정확한 질문을 했고이 디자인의 근거를 이해하고 싶었습니다.

받아 들여진 대답은 근거가 옳았습니다. 이 기능을 디자인 한 팀의 확인 사항은 다음과 같습니다 (강조 광산).

두 가지 새로운 유형이 프레임 워크의 기초를 형성합니다. A CancellationToken는 ‘잠재 취소 요청’을 나타내는 구조체입니다. 이 구조체는 매개 변수로 메서드 호출에 전달되며 메서드는 해당 요청을 폴링하거나 취소 요청시 실행되도록 콜백을 등록 할 수 있습니다. A CancellationTokenSource는 취소 요청을 시작하는 메커니즘을 제공하는 클래스 Token
이며 관련 토큰을 얻기위한 속성이 있습니다. 이 두 클래스를 하나로 결합하는 것은 당연한 것이 었지만,이 설계를 통해 두 가지 주요 작업 (취소 요청 시작 및 취소 관찰 및 응답)을 완전히 분리 할 수 ​​있습니다. 특히, CancellationToken요청 만받는 메소드 는 취소 요청을 관찰 할 수 있지만이를 취소 할 수는 없습니다.

링크 : .NET 4 취소 프레임 워크

제 생각 CancellationToken에는 상태 만 관찰 할 수 있고 변경할 수 없다는 사실 은 매우 중요합니다. 당신은 사탕처럼 토큰을 나눠 줄 수 있고 당신 이외의 다른 누군가가 그것을 취소 할 것을 걱정하지 마십시오. 적대적인 제 3 자 코드로부터 사용자를 보호합니다. 예, 기회는 적지 만 개인적으로 그 보증을 좋아합니다.

또한 API를 더 깨끗하게 만들고 실수로 인한 실수를 피하며 더 나은 구성 요소 디자인을 촉진한다고 생각합니다.

이 두 클래스에 대한 퍼블릭 API를 살펴 보자.

CancellationToken API

CancellationTokenSource API

LongRunningFunction을 작성할 때 이들을 결합하면 사용하지 말아야 할 ‘Cancel’의 여러 과부하와 같은 메소드가 표시됩니다. 개인적으로 Dispose 메서드도 싫어합니다.

현재의 클래스 디자인은 ‘성공의 원칙’철학을 따르는 것으로 생각되며, 개발자가 Task취소 를 처리 할 수있는 더 나은 구성 요소를 만든 다음 여러 가지 방식으로 함께 구성하여 복잡한 워크 플로를 만들도록 안내합니다.

질문을하겠습니다. 토큰의 목적이 무엇인지 궁금하십니까? 나에게는 이해가되지 않았다. 그런 다음 Managed Threads에서 Cancel을 읽고 모든 것이 명확 해졌습니다.

TPL의 취소 프레임 워크 디자인은 절대 최고 수준이라고 생각합니다.


답변

기술적 인 이유가 아니라 의미적인 이유로 분리되어 있습니다. CancellationTokenILSpy 에서 구현을 살펴보면 래퍼 일뿐입니다 CancellationTokenSource(따라서 참조를 전달하는 것과 다른 성능 측면은 아닙니다).

그것들은 이러한 기능 분리를 제공하여 상황을보다 예측 가능하게 만듭니다 CancellationToken. 물론, 메소드는 여전히을 던질 수 TaskCancelledException있지만 CancellationToken자체 및 동일한 토큰을 참조하는 다른 메소드는 안전합니다.


답변

CancellationToken많은 사본 인해 방법에 따라 전달하기에 존재할 수 있도록 구조체이다.

CancellationTokenSource세트 호출 토큰의 모든 사본의 상태 Cancel소스에. 이 MSDN 페이지를 참조하십시오

디자인의 이유는 우려의 분리와 구조체의 속도의 문제 일 수 있습니다.


답변

CancellationTokenSource‘일’이 문제가 어떤 이유로 취소입니다. CancellationToken발행 한 모든에 취소를 ‘파견’하는 방법이 필요합니다 . 예를 들어 ASP.NET은 요청이 중단 될 때 작업을 취소 할 수 있습니다. 각 요청에는 CancellationTokenSource취소 한 모든 토큰에 취소가 전달됩니다.

이것은 단위 테스트 BTW에 좋습니다-자신 만의 취소 토큰 소스를 만들고, 토큰을 얻고 Cancel, 소스를 호출 하고, 취소를 처리해야하는 코드에 토큰을 전달하십시오.


답변