CancellationToken이 CancellationTokenSource와 다른 이유는 무엇입니까?
.NET CancellationToken 구조체가 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 == "취소 청취자"
나는 똑같은 질문을 했고이 디자인의 근거를 이해하고 싶었습니다.
받아 들여진 대답은 근거가 옳았습니다. 이 기능을 디자인 한 팀의 확인 사항은 다음과 같습니다 (강조 광산).
두 가지 새로운 유형이 프레임 워크의 기초를 형성합니다. CancellationToken은 '잠재 취소 요청'을 나타내는 구조체입니다. 이 구조체는 매개 변수로 메서드 호출에 전달되며 메서드는 해당 요청을 폴링하거나 취소 요청시 실행되도록 콜백을 등록 할 수 있습니다. CancellationTokenSource는 취소 요청을 시작하는 메커니즘을 제공하는 클래스이며 관련 토큰을 얻기위한 Token 속성이 있습니다. 이 두 클래스를 하나로 결합하는 것은 당연한 것이 었지만,이 설계를 통해 두 가지 주요 작업 (취소 요청 시작 및 취소 관찰 및 응답)을 완전히 분리 할 수 있습니다. 특히 CancellationToken 만 사용하는 메서드는 취소 요청을 관찰 할 수는 있지만 취소 할 수는 없습니다.
링크 : .NET 4 취소 프레임 워크
제 생각에, CancellationToken은 상태를 관찰 할 수만 있고 변경할 수 없다는 사실은 매우 중요합니다. 당신은 사탕처럼 토큰을 나눠 줄 수 있고 당신 이외의 다른 누군가가 그것을 취소 할 것을 걱정하지 않아도됩니다. 적대적인 제 3 자 코드로부터 사용자를 보호합니다. 예, 기회는 적지 만 개인적으로 그 보증을 좋아합니다.
또한 API를 더 깨끗하게 만들고 실수로 인한 실수를 피하며 더 나은 구성 요소 디자인을 촉진한다고 생각합니다.
이 두 클래스에 대한 퍼블릭 API를 살펴 보자.
LongRunningFunction을 작성할 때 이들을 결합하면 사용하지 말아야 할 'Cancel'의 여러 과부하와 같은 메소드가 표시됩니다. 개인적으로 Dispose 메서드도 싫어합니다.
현재의 클래스 디자인은 '성공의 피트'철학을 따르고 있다고 생각합니다. 개발자가 작업 취소를 처리 할 수있는 더 나은 구성 요소를 만든 다음 여러 가지 방식으로 함께 구성하여 복잡한 워크 플로를 만들도록 안내합니다.
질문을하겠습니다. 토큰의 목적이 무엇인지 궁금하십니까? 이해가되지 않았습니다. 그런 다음 Managed Threads에서 Cancel을 읽고 모든 것이 명확 해졌습니다.
TPL의 취소 프레임 워크 디자인은 절대 최고 수준이라고 생각합니다.
기술적 인 이유가 아니라 의미적인 이유로 분리되어 있습니다. CancellationToken
ILSpy 에서 구현을 살펴보면 래퍼 일뿐입니다 CancellationTokenSource
(따라서 참조를 전달하는 것과 다른 성능 측면은 아닙니다).
They provide this separation of functionality to make things more predictable: when you pass a method a CancellationToken
, you know you're still the only one that can cancel it. Sure, the method could still throw a TaskCancelledException
, but the CancellationToken
itself -- and any other methods referencing the same token -- would remain safe.
The CancellationToken is a struct so many copies could exist due to passing it along to methods.
The CancellationTokenSource sets the state of ALL copies of a token when calling Cancel on the source. See this MSDN page
The reason for the design might be just a matter of seperation of concerns and the speed of a struct.
The CancellationTokenSource is the 'thing' that issues the cancellation, for whatever reason. It needs a way to 'dispatch' that cancellation to all the CancellationToken's it has issued. That's how, for example, ASP.NET can cancel operations when a request is aborted. Each request has a CTSource that forwards the cancellation to all the tokens it has issued.
This great for unit testing BTW - create your own cancellation token source, get a token, call Cancel on the soource, and pass the token to your code that has to handle the cancellation.
My "theory" is that the role of CancellationToken is to provide a thread-safe wrapper to avoid contention.
클래스가 하나뿐이므로 고유 한 인스턴스가 참조 사본과 함께 사용되고 취소를 위해 핸들러를 등록하는 스레드가 많은 경우이 클래스는 잠금을 사용하여 동시성을 관리하여 성능을 저하시켜야합니다.
와 반면 CancellationToken 구조체 는 경합 각각의 스레드에 대한 각 콜백 - 큐의 사본을 가지고있다.
이것은 순수한 추측이며 완전히 잘못 되었거나이 디자인에 대한 다른 좋은 이유가있을 수 있습니다.
확실한 유일한 이유는 적어도 하나의 정당한 이유가 있다는 것입니다. 그리고 이러한 종류의 결정은 기술을 사용할 때 귀중한 통찰력이므로 더 이상 문서화되지 않은 것이 부끄러운 일입니다.
'IT박스' 카테고리의 다른 글
OpenSSL 연결을 거부하는 Homebrew (0) | 2020.07.18 |
---|---|
LINQ to SQL : 여러 열에서 여러 조인 (0) | 2020.07.18 |
java.lang.OutOfMemoryError : Maven의 Java 힙 공간 (0) | 2020.07.18 |
git이 경로별로 하드 / 소프트 리셋을 수행 할 수없는 이유는 무엇입니까? (0) | 2020.07.17 |
PyLint 메시지 : logging-format-interpolation (0) | 2020.07.17 |