.NET의 동시성 및 주립 도서관은 네트워크 통화에서 빛납니다.
https://www.nuget.org/packages/serviceconcurrency/에서 Nuget 패키지
동시성 및 상태를 처리하기위한 라이브러리, 주로 웹 서비스를 요구하는 코드를위한 도서관.
첫째, 불필요한 통화가 발생하는 것을 방지합니다. 일치하는 인수가있는 호출이 이미 비행 중일 때, 동시 발신자가 주차되어 있으며 원래 요청이 완료되면 재개됩니다. 논쟁이 컬렉션 인 경우 이미 비행중인 엔티티가 제거되었습니다.
둘째, 가치가 반환 요청 상태를 캐시합니다. 주어진 요청에 따라 캐시 된 값이 존재하면 통화 대신 반환됩니다. 이 값은 언제든지 액세스 할 수 있으므로 코드에서 추가 백업 필드가 필요하지 않습니다. 논쟁이 컬렉션 인 경우 캐시 된 엔티티는 논쟁에서 벗어납니다.
이 라이브러리는 내부 데이터 캐싱에 ImemoryCache를 사용합니다.
다음은 ServiceConcurrency가 당신을 위해 처리 할 수있는 몇 가지가 있습니다. 더 심층적 인 예는이 문서의 후반부에서 찾을 수 있습니다.
getSessionToken ()은 첫 번째 호출이 이루어진 후 캐시 된 값을 반환합니다. getsessionToken ()이 동시에 호출되는 동안 아직 값이 캐시되지 않은 경우 retchsessionToken ()에 대한 한 번의 호출만이 만들어지고 다른 동시 호출은 값을 사용할 수있을 때까지 생성됩니다.
private ServiceConcurrency . ReturnsValue < string > sessionTokenState =
new ServiceConcurrency . ReturnsValue < string > ( ) ;
public async Task < string > GetSessionToken ( )
{
return await this . sessionTokenState . Execute ( this . FetchSessionToken ) ;
}위와 동일하지만 인수 컬렉션은 이미 캐싱되거나 비행중인 값이 제거되었습니다. 따라서 FetchUserProfiles ()는 ID로 두 번 이상 호출되지 않습니다.
private ServiceConcurrency . TakesEnumerationArgReturnsValue < Guid , UserProfile > userProfilesState =
new ServiceConcurrency . TakesEnumerationArgReturnsValue < Guid , UserProfile > ( ) ;
public async Task < IEnumerable < UserProfile > > GetUserProfiles ( IEnumerable < Guid > userProfileIds )
{
return await this . userProfilesState . Execute (
this . FetchUserProfiles ,
( guid , results ) => results . SingleOrDefault ( t => t . Id == guid ) ,
userProfileIds
) ;
} 이 라이브러리에는 네 가지 수업이 있습니다.
Noargnovalue
한 번에 하나의 활성 호출 만 허용하여 동시 통화를 방지합니다. 동시 통화는 활성 호출이 완료 될 때까지 기다립니다.
returnsValue <TValue>
한 번의 호출만이 이루어지고 후속 통화는 캐시에서 값을 가져옵니다. 또한 동시 통화가 한 번에 하나의 활성 호출 만 허용함으로써 동시 통화가 발생하는 것을 방지합니다.
TakesArg <Targ>
인수 당 시간에 한 번의 활성 호출 만 허용하여 동시 호출이 완료 될 때까지 대기 할 때 동일한 인수를 공유 할 때 동시 호출을 방지합니다.
TakesArgreturnsValue <targ, tvalue>
주어진 인수의 경우 하나의 호출만이 이루어지고 후속 통화는 캐시에서 값을 가져옵니다. 또한 인수 당 한 번에 하나의 활성 호출 만 허용하여 동시 호출이 발생하는 것을 방지합니다. 여기서 동시 통화는 활성 호출이 완료 될 때까지 기다립니다.
TakesEnumerationArg <Targ>
동시 호출은 인수 컬렉션에서 주어진 인수에 대해 한 번만 실행됩니다.
인수 수집은 작업이 이미 비행중인 값이 제거되었습니다.
따라서 [ "a", "b", "c"] 및 [ "b", "c", "d"]로 동시에 호출하면 [ "a", "b", "c"]와 [ "d"]가있는 한 번의 호출이 발생합니다.
TakesEnumerationArgreturnsValue <targ, tvalue>
첫 번째 호출과 동시 호출은 인수 컬렉션에서 주어진 인수에 대해 한 번만 실행됩니다. 후속 통화는 캐시에서 값을 가져옵니다.
인수 수집은 캐시 된 값이 존재하거나 작업이 이미 비행중인 값이 제거되었습니다.
따라서 [ "a", "b", "c"] 및 [ "b", "c", "d"]로 동시에 호출하면 [ "a", "b", "c"]와 [ "d"]가있는 한 번의 호출이 발생합니다. 다음에 "a", "b", "c"또는 "d"가 호출되면 컬렉션에서 벗겨지고 캐시에서 값을 가져옵니다.
모든 ServiceConcurrency 객체에는 매개 변수가없는 생성자가 있으며,이 경우 내부 ImemoryCache가 생성됩니다.
값을 반환하는 모든 ServiceConcurrency 객체에는 모든 ServiceConcurrency 객체와 캐시를 공유하려는 경우 ImemoryCache 객체를 수용하는 생성자가 있습니다. 그렇다면 항목에서 고유 키를 사용해야합니다.
T Execute ( .. . )특정 요청을 실행합니다. 외부 호출을위한 콜백을 제공합니다. 인수와 반환 유형이 ServiceConcurrency 유형에 따라 다르므로 자세한 내용은 예제를 참조하십시오. 결과 값은 캐시되고 콜백에서 귀하에게 제공됩니다.
void Reset ( )내부 상태, 즉 프로세스 및 내부 캐시의 통화에 대한 상태를 재설정합니다 (ServiceConcurrency 객체가 값을 반환하는 경우).
bool IsExecuting ( )ServiceConcurrency 객체가 현재 특정 요청을 실행하고 있는지 여부를 반환합니다.
다음 방법은 값을 반환하는 ServiceConcurrency 객체에서만 사용할 수 있습니다.
void ResetCache ( )내부 캐시를 재설정합니다. Reset ()에서도 호출됩니다.
bool TryGetValue ( TArg key , out TValue value )캐시에서 값을 가져옵니다.
void Set ( TArg key , TValue value )캐시 세터 드문 경우 캐시를 수동으로 조작해야 할 수도 있습니다.
void Remove ( TArg key )캐시에서 값을 제거합니다.
bool ContainsKey ( TArg key )캐시에 항목이 있는지 확인합니다.
TValue this [ TArg key ]캐시 항목을 설정하고 가져 오기위한 배열 연산자. 항목이 존재하지 않으면 getter에서 keynotfoundexception을 던집니다.
IEnumerator < KeyValuePair < TArg , TValue > > GetEnumerator ( )
IEnumerator IEnumerable . GetEnumerator ( )내부 캐시에 대한 열거 자. Foreach 및 LINQ 문에서 객체를 사용할 수 있습니다.
void Dispose ( ) bool IsCacheShared 거짓 인 경우 내부 캐시 처분. 공유 캐시 인 경우 대신 ResetCache 호출합니다.
TValue Value ;returnsvalue <tvalue>에서만. 이것은 단일 캐시 된 물체입니다.
다음 속성은 값을 반환하는 ServiceConcurrency 객체에서만 사용할 수 있습니다.
MemoryCacheEntryOptions CacheEntryOptions ;이 옵션은 값이 캐시 될 때 내부적으로 사용됩니다. 이를 편집하면 만료, 캐시 크기 등을 설정할 수 있습니다. 자세한 내용은 MemoryCacheOptions를 참조하십시오.
bool IsCacheShared ;getter 만. 캐시가 공유되는지 여부를 나타냅니다.
execute ()는 선택적 값 변환기를 수락하여 반환하고 캐싱하기 전에 페치 된 값을 수정할 수 있습니다. 이것은 값을 반환하는 ServiceConcurrency 객체에서만 사용할 수 있습니다.
private ServiceConcurrency . ReturnsValue < string > lastName =
new ServiceConcurrency . ReturnsValue < string > ( ) ;
private const string FirstName = "John" ;
public async Task < string > GetFullName ( )
{
return await this . lastName . Execute (
this . GetLastName ,
( lastName ) => $ " { FirstName } { lastName } " ;
) ;
}ServiceConcurrency 오브젝트는 또한 내부 요청의 값 유형을 선언하는 추가 매개 변수를 수락합니다. 이것이 지정되면 값 변환기도 소스 유형과 대상 유형 사이를 변환합니다. 이는 execute ()가 호출 한 요청이 원하는 백업 필드와 다른 유형 인 경우에 유용합니다.
// FetchChatRooms() returns an IEnumerable<ChatRoom>, chatRoomMap handles it as Dictionary<Guid, ChatRoom>
private ServiceConcurrency . ReturnsValue < IEnumerable < ChatRoom > , Dictionary < Guid , ChatRoom > > chatRoomMap =
new ServiceConcurrency . ReturnsValue < IEnumerable < ChatRoom > , Dictionary < Guid , ChatRoom > > ( ) ;
public async Task < IEnumerable < ChatRoom > > UpdateChatRooms ( )
{
return ( await this . chatRoomMap . Execute (
this . FetchChatRooms ,
( chatRooms ) => chatRooms . ToDictionary ( t => t . Id , t => t ) // cache as id -> chatroom map
) ) ? . Values ;
}
public ChatRoom GetChatRoom ( Guid chatRoomId )
{
ChatRoom chatRoom ;
if ( this . chatRoomMap . Value . TryGetValue ( chatRoomId , out chatRoom ) ) // value is Dictionary<Guid, ChatRoom>
return chatRoom ;
return null ;
} using System ;
using System . Collections . Generic ;
using System . Threading . Tasks ;
using System . Linq ;
public class MyService : IDisposable
{
////////////////////////////////////////////////////////////////////////////
// NoArgNoValue example
private ServiceConcurrency . NoArgNoValue simpleCallState =
new ServiceConcurrency . NoArgNoValue ( ) ;
// Concurrent calls won't invoke the callback multiple times - only the first
// call will invoke it, and the rest will wait until it finishes.
public async Task CallSomething ( )
{
await this . simpleCallState . Execute (
async ( ) =>
{
Console . WriteLine ( "CallSomething call in flight" ) ;
await Task . Delay ( 100 ) ;
}
) ;
}
////////////////////////////////////////////////////////////////////////////
// ReturnsValue example
private ServiceConcurrency . ReturnsValue < string > returnsValueState =
new ServiceConcurrency . ReturnsValue < string > ( ) ;
// Only one call will be made and subsequent calls will fetch the value from
// cache. Also prevents any concurrent calls from occurring, by allowing only
// one active call at a time, where concurrent calls will wait for the active
// call to finish.
public async Task < string > FetchSomething ( )
{
return await this . returnsValueState . Execute (
async ( ) =>
{
Console . WriteLine ( "FetchSomething call in flight" ) ;
await Task . Delay ( 100 ) ;
return "Hello world!" ;
}
) ;
}
////////////////////////////////////////////////////////////////////////////
// TakesArg example
private ServiceConcurrency . TakesArg < Guid > takesArgState =
new ServiceConcurrency . TakesArg < Guid > ( ) ;
// Prevents concurrent calls when sharing the same argument, by allowing only
// one active call at a time per argument, where concurrent calls will wait for
// the active call to finish.
public async Task PostSomething ( Guid someId )
{
await this . takesArgState . Execute (
async ( Guid id ) =>
{
Console . WriteLine ( $ "PostSomething call in flight, for argument { id } " ) ;
await Task . Delay ( 100 ) ;
} ,
someId
) ;
}
////////////////////////////////////////////////////////////////////////////
// TakesArgReturnsValue example
private ServiceConcurrency . TakesArgReturnsValue < Guid , string > takesArgReturnsValueState =
new ServiceConcurrency . TakesArgReturnsValue < Guid , string > ( ) ;
// For a given argument, only one call will be made and subsequent calls will
// fetch the value from cache. Also prevents any concurrent calls from occurring,
// by allowing only one active call at a time per argument, where concurrent
// calls will wait for the active call to finish.
public async Task < string > FetchSomethingFor ( Guid someId )
{
return await this . takesArgReturnsValueState . Execute (
async ( Guid id ) =>
{
Console . WriteLine ( $ "FetchSomethingFor call in flight, for argument { id } " ) ;
await Task . Delay ( 100 ) ;
return $ "The guid is { id } " ;
} ,
someId
) ;
}
////////////////////////////////////////////////////////////////////////////
// TakesEnumerationArg example
private ServiceConcurrency . TakesEnumerationArg < Guid > takesEnumerationArgState =
new ServiceConcurrency . TakesEnumerationArg < Guid > ( ) ;
// Concurrent calls will execute only once for a given argument in the argument
// collection.
//
// The argument collection is stripped of values for which an operation is already
// in flight.
//
// So simultaneously calling with ["A", "B", "C"] and ["B", "C", "D"] will result
// in one call with ["A", "B", "C"] and one with ["D"].
public async Task PostCollection ( IEnumerable < Guid > someIds )
{
await this . takesEnumerationArgState . Execute (
async ( IEnumerable < Guid > ids ) =>
{
Console . WriteLine ( $ "PostCollection call in flight, for arguments { ids . Select ( t => t ) } " ) ;
await Task . Delay ( 100 ) ;
} ,
someIds
) ;
}
////////////////////////////////////////////////////////////////////////////
// TakesEnumerationArgReturnsValue example
private ServiceConcurrency . TakesEnumerationArgReturnsValue < Guid , ExampleClass > takesEnumArgReturnsValueState =
new ServiceConcurrency . TakesEnumerationArgReturnsValue < Guid , ExampleClass > ( ) ;
public class ExampleClass
{
public Guid Id { get ; set ; }
}
// The first call, and any concurrent calls, will execute only once for a
// given argument in the argument collection. Subsequent calls will fetch value
// from cache.
//
// The argument collection is stripped of values for which a cached value exists
// or an operation is alraedy in flight.
//
// So simultaneously calling with ["A", "B", "C"] and ["B", "C", "D"] will
// result in one call with ["A", "B", "C"] and one with ["D"].
// The next time "A", "B", "C" or "D" is called with, it will be stripped from
// the collection and a value for it will be fetched from the cache.
public async Task < IEnumerable < ExampleClass > > FetchCollectionForThese ( IEnumerable < Guid > someIds )
{
return await this . takesEnumArgReturnsValueState . Execute (
async ( IEnumerable < Guid > ids ) =>
{
Console . WriteLine ( $ "FetchCollectionForThese call in flight, for arguments { ids . Select ( t => t ) } " ) ;
await Task . Delay ( 100 ) ;
return ids . Select ( t => new ExampleClass ( )
{
Id = t
} ) ;
} ,
// a mapper from arg to result is required - should return the corresponding value for the passed argument
( Guid id , IEnumerable < ExampleClass > result ) => result . SingleOrDefault ( t => t . Id == id ) ,
someIds
) ;
}
void Dispose ( )
{
this . simpleCallState . Dispose ( ) ;
this . returnsValueState . Dispose ( ) ;
this . takesArgState . Dispose ( ) ;
this . takesArgReturnsValueState . Dispose ( ) ;
this . takesEnumerationArgState . Dispose ( ) ;
this . takesEnumArgReturnsValueState . Dispose ( ) ;
}
}