Orleans 에는 변경할 수 없는 형식이 포함된 메시지 직렬화와 관련된 오버헤드를 방지하는 데 사용할 수 있는 기능이 있습니다. 이 섹션에서는 관련 컨텍스트부터 기능 및 해당 애플리케이션에 대해 설명합니다.
Orleans의 직렬화
그레인 메서드를 호출할 때 런타임은 Orleans 메서드 인수의 전체 복사본을 만들고 이러한 복사본의 요청을 형성합니다. 이렇게 하면 데이터가 호출된 곡물로 전달되기 전에 인수 개체를 수정하는 호출 코드로부터 보호됩니다.
호출된 곡물이 다른 사일로에 있는 경우 복사본은 결국 바이트 스트림으로 직렬화되고 네트워크를 통해 대상 사일로로 전송되며, 여기서 개체로 다시 역직렬화됩니다. 호출된 곡물이 동일한 사일로에 있는 경우 복사본은 호출된 메서드에 직접 전달됩니다.
반환 값은 먼저 복사한 다음 직렬화 및 역직렬화와 같은 방식으로 처리됩니다.
복사, 직렬화 및 역직렬화의 세 프로세스는 모두 개체 ID를 존중합니다. 즉, 동일한 개체가 포함된 목록을 두 번 전달하는 경우 수신 측은 동일한 값을 가진 두 개체가 아닌 동일한 개체가 있는 목록을 두 번 가져옵니다.
복사 최적화
대부분의 경우 심층 복사가 필요하지 않습니다. 예를 들어 웹 프런트 엔드가 클라이언트에서 바이트 배열을 수신하고 바이트 배열을 포함한 해당 요청을 처리할 곡물로 전달하는 시나리오를 고려합니다. 프런트 엔드 프로세스는 배열을 그레인에 전달한 후 배열에서 아무 작업도 수행하지 않습니다. 특히 향후 요청에는 배열을 다시 사용할 수 없습니다. 그레인 내부에서는 입력 데이터를 가져오기 위해 바이트 배열이 구문 분석되지만, 수정되지는 않습니다. 그레인은 만든 다른 바이트 배열을 웹 클라이언트에 반환하고 반환한 직후 배열을 삭제합니다. 웹 프런트 엔드는 결과 바이트 배열을 수정하지 않고 클라이언트에 다시 전달합니다.
이러한 시나리오에서는 요청 또는 응답 바이트 배열을 복사할 필요가 없습니다. 아쉽게도 런타임은 Orleans 웹 프런트 엔드 또는 그레인이 나중에 배열을 수정하는지 여부를 확인할 수 없으므로 이를 자동으로 파악할 수 없습니다. 이상적으로 .NET 메커니즘은 값이 더 이상 수정되지 않음을 나타냅니다. 그 기능이 부족하기 때문에, 우리는 Orleans-특정 메커니즘, Immutable<T> 래퍼 클래스와 ImmutableAttribute를 추가했습니다.
[Immutable] 특성을 사용하여 형식, 매개 변수, 속성 또는 필드를 변경할 수 없음으로 표시합니다.
사용자 정의 형식의 경우 형식에 ImmutableAttribute 추가할 수 있습니다. 이렇게 하면 직렬 변환기가 이 형식의 인스턴스를 복사하지 않도록 합니다 Orleans . 다음 코드 조각은 변경할 수 없는 형식을 나타내는 데 사용하는 [Immutable] 방법을 보여 줍니다. 이 형식은 전송 중에 복사되지 않습니다.
[Immutable]
public class MyImmutableType
{
public int MyValue { get; }
public MyImmutableType(int value)
{
MyValue = value;
}
}
때때로 개체를 제어하지 못할 수도 있습니다. 예를 들어 객체 간에 보내는 List<int>일 수 있습니다. 다른 경우에는 개체의 일부가 변경할 수 없지만 다른 부분은 변경할 수 없습니다. 이러한 경우 Orleans 추가 옵션을 지원합니다.
매개 변수별로 메서드 서명에 ImmutableAttribute를 포함할 수 있습니다.
public interface ISummerGrain : IGrain { // `values` will not be copied. ValueTask<int> Sum([Immutable] List<int> values); }포함된 형식의 인스턴스가 복사될 때 개별 속성 및 필드를 복사하지 않도록 ImmutableAttribute로 표시하십시오.
[GenerateSerializer] public sealed class MyType { [Id(0), Immutable] public List<int> ReferenceData { get; set; } [Id(1)] public List<int> RunningTotals { get; set; } }
Immutable<T> 사용
래퍼 클래스를 Immutable<T> 사용하여 값을 변경할 수 없는 것으로 간주할 수 있음을 나타냅니다. 즉, 기본 값은 수정되지 않으므로 안전한 공유를 위해 복사가 필요하지 않습니다.
Immutable<T>를 사용할 경우, 공급자나 값을 받는 자 모두 나중에 이를 수정하지 않을 것을 의미합니다. 그것은 일방적인 것이 아니라 상호, 이중적인 약속입니다.
당신의 그레인 인터페이스에서 Immutable<T> 대신 Immutable<T>을 사용하려면 T을 전달하세요. 예를 들어 위에서 설명한 시나리오에서 그레인 메서드는 다음과 같습니다.
Task<byte[]> ProcessRequest(byte[] request);
그러면 다음이 됩니다.
Task<Immutable<byte[]>> ProcessRequest(Immutable<byte[]> request);
Immutable<T>을(를) 생성하려면 생성자를 사용하세요.
Immutable<byte[]> immutable = new(buffer);
변경할 수 없는 래퍼 안의 값을 얻으려면 .Value 속성을 사용하세요.
byte[] buffer = immutable.Value;
Orleans 불변성
'를 위해 Orleans불변성은 엄격한 명령문입니다. 데이터 항목의 내용은 항목의 의미 체계를 변경하거나 동시에 액세스하는 다른 스레드를 방해할 수 있는 방식으로 수정되지 않습니다. 이를 보장하는 가장 안전한 방법은 단순히 항목을 전혀 수정하지 않는 것입니다. 논리적 불변성보다는 비트 불변성을 사용합니다.
경우에 따라 논리적 불변성으로 완화해도 안전하지만, 변경 코드가 스레드로부터 안전하게 보호되도록 주의해야 합니다. 멀티스레딩 처리는 Orleans 컨텍스트에서 복잡하고 드문 경우이기 때문에, 이 접근 방식을 권장하지 않으며 비트 단위의 불변성을 고수할 것을 권장합니다.
.NET