Eine Parallelitäts- und Staatsbibliothek für .NET strahlt in Netzwerkaufrufen.
Nuget -Paket erhältlich unter https://www.nuget.org/packages/serviceconcurrency/
Eine Bibliothek zur Behandlung von Parallelität und Status, hauptsächlich für Code, der auf Webdienste aufruft.
Erstens verhindert es unnötige Anrufe. Wenn ein Anruf mit passenden Argumenten bereits im Flug ist, wird der gleichzeitige Anrufer geparkt und wird wieder aufgenommen, wenn die Ursprungsanforderung abgeschlossen ist. Wenn das Argument eine Sammlung ist, werden bereits im Flug stehende Unternehmen entzogen.
Zweitens zwischengespeichert es den Wertverkehrszustand. Wenn ein zwischengespeicherter Wert für eine bestimmte Anfrage besteht, wird er zurückgegeben, anstatt dass ein Anruf getätigt wird. Dieser Wert kann jederzeit zugegriffen werden, wodurch ein Bedarf an zusätzlichen Sicherungsfeldern in Ihrem Code verhindern wird. Wenn das Argument eine Sammlung ist, werden zwischengespeicherte Wesenheiten aus dem Argument entzogen.
Diese Bibliothek verwendet Imemorycache für die interne Daten zwischen Daten.
Hier sind ein paar Dinge, die die ServiceConcurrency für Sie erfüllen können. Eingehende Beispiele finden Sie in späteren Abschnitten dieses Dokuments.
GetSessionToken () gibt nach einem ersten Anruf einen zwischengespeicherten Wert zurück. Wenn GetSessionToken () gleichzeitig aufgerufen wird, während es noch keinen Wert hat, wird nur ein Aufruf an FetchSessionToken () getroffen und die anderen gleichzeitigen Anrufe ergeben, bis ein Wert verfügbar ist.
private ServiceConcurrency . ReturnsValue < string > sessionTokenState =
new ServiceConcurrency . ReturnsValue < string > ( ) ;
public async Task < string > GetSessionToken ( )
{
return await this . sessionTokenState . Execute ( this . FetchSessionToken ) ;
}Gleich wie oben, aber die Argumentsammlung wird von bereits zwischengespeicherten Werten oder im Flug gestreift. FetchuserProfiles () wird also nie mehr als einmal mit einer ID aufgerufen.
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
) ;
} In dieser Bibliothek gibt es vier Klassen:
Noargnovalue
Verhindert gleichzeitige Anrufe, indem nur einen aktiven Anruf gleichzeitig zuzulassen, bei dem gleichzeitige Anrufe auf den aktiven Anruf warten.
ReturnSValue <VERSCHAFTE>
Es wird nur ein Anruf getätigt und nachfolgende Anrufe holen den Wert aus dem Cache. Verhindert auch, dass gleichzeitige Anrufe auftreten, indem nur ein aktiver Anruf gleichzeitig zulässig ist, bei dem gleichzeitige Anrufe auf den aktiven Anruf warten.
Takesarg <targ>
Verhindert gleichzeitige Anrufe beim Teilen desselben Arguments, indem nur einen aktiven Anruf zu einem Zeitpunkt pro Argument zuzulassen, bei dem gleichzeitige Anrufe auf den aktiven Anruf warten.
TakesargreturnsValue <targ, tvalue>
Für ein bestimmtes Argument wird nur ein Anruf getätigt, und nachfolgende Anrufe holen den Wert aus dem Cache. Verhindert auch, dass gleichzeitige Aufrufe auftreten, indem nur ein aktiver Anruf zu einem Zeitpunkt pro Argument zugelassen wird, bei dem gleichzeitige Anrufe auf den aktiven Anruf warten.
TakesEnumerationArg <targ>
Gleichzeitige Anrufe werden nur einmal für ein bestimmtes Argument in der Argumentsammlung ausgeführt.
Die Argumentsammlung wird von Werten befreit, für die sich bereits eine Operation im Flug befindet.
Gleichzeitig mit ["A", "B", "C" und ["B", "C", "D", "D"], wird zu einem Anruf mit ["A", "B", "C"] und einem mit ["D"] führen.
TakesEnumerationArgreturnsValue <targ, tvalue>
Der erste Anruf und alle gleichzeitigen Anrufe werden nur einmal für ein bestimmtes Argument in der Argumentsammlung ausgeführt. Nachfolgende Anrufe holen den Wert aus dem Cache.
Die Argumentsammlung wird von Werten befreit, für die ein zwischengespeicherter Wert existiert oder ein Betrieb bereits im Flug ist.
Gleichzeitig mit ["A", "B", "C" und ["B", "C", "D", "D"], wird zu einem Anruf mit ["A", "B", "C"] und einem mit ["D"] führen. Das nächste Mal, dass "A", "B", "C" oder "D" aufgerufen wird, wird es aus der Sammlung entzogen und ein Wert dafür wird aus dem Cache abgerufen.
Alle ServicEConcurrency -Objekte haben einen parameterlosen Konstruktor. In diesem Fall wird ein interner Imemorycache erstellt.
Alle ServicEConcurrency -Objekte, die Werte zurückgeben, haben auch einen Konstruktor, der ein Imemorycache -Objekt akzeptiert, falls Sie den Cache mit allen ServicEConcurrency -Objekten freigeben möchten. Wenn Sie dies tun, stellen Sie bitte sicher, dass Sie einzigartige Schlüssel für die Einträge verwenden.
T Execute ( .. . )Führt eine bestimmte Anfrage aus. Sie geben einen Rückruf für den Anruf von außen an. Weitere Informationen finden Sie in den Beispielen, da die Argumente und Rückgabetypen eine spezifische ServicE -Währungstyp sind. Der resultierende Wert wird zwischengespeichert und Ihnen in Ihrem Rückruf zur Verfügung gestellt.
void Reset ( )Setzt den internen Zustand, dh Status für Aufrufe in Prozess und internem Cache, zurück (falls das Objekt des ServicEConcurrency -Objekts Werte zurückgibt).
bool IsExecuting ( )Gibt zurück, ob das ServiceConcurrency -Objekt derzeit eine bestimmte Anforderung ausführt.
Die folgenden Methoden sind nur in ServicEConcurrency -Objekten verfügbar, die Werte zurückgeben.
void ResetCache ( )Setzt den internen Cache zurück. Auch von reset () genannt.
bool TryGetValue ( TArg key , out TValue value )Erholt einen Wert aus dem Cache.
void Set ( TArg key , TValue value )Ein Cache -Setter im seltenen Fall müssen Sie möglicherweise den Cache manuell manipulieren.
void Remove ( TArg key )Entfernt einen Wert aus dem Cache.
bool ContainsKey ( TArg key )Überprüft, ob ein Eintrag im Cache vorhanden ist.
TValue this [ TArg key ]Array -Operator zum Einstellen und Erhalten von Cache -Einträgen. Wirft eine KeynotFoundException in den Getter, wenn ein Eintrag nicht vorhanden ist.
IEnumerator < KeyValuePair < TArg , TValue > > GetEnumerator ( )
IEnumerator IEnumerable . GetEnumerator ( )Aufzähler für den internen Cache. Ermöglicht die Verwendung der Objekte in Foreach- und Linq -Anweisungen.
void Dispose ( ) Entsorgung des internen Cache, wenn bool IsCacheShared ist falsch. Wenn es sich um einen gemeinsam genutzten Cache handelt, werden stattdessen nur ResetCache aufgerufen.
TValue Value ;Nur im Rückkehr von TVAlue>. Dies ist das einzelne zwischengespeicherte Objekt.
Die folgenden Eigenschaften sind nur in ServicEConcurrency -Objekten verfügbar, die Werte zurückgeben.
MemoryCacheEntryOptions CacheEntryOptions ;Diese Optionen werden intern verwendet, wenn ein Wert zwischengespeichert wird. Wenn Sie diese bearbeiten, können Sie Ablauf, Cache -Größen usw. festlegen. Weitere Informationen finden Sie unter SpeichercacheOptions.
bool IsCacheShared ;Nur Getter. Bezeichnet, ob der Cache geteilt wird oder nicht.
Execute () akzeptiert einen optionalen Wertkonverter, der den abgerufenen Wert vor zurückgegeben und zwischengespeichert wird. Dies ist nur in den ServicEConcurrency -Objekten verfügbar, die Werte zurückgeben.
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 -Objekte akzeptieren auch einen zusätzlichen Parameter, der den Werttyp der internen Anforderung deklariert. Wenn dies angegeben ist, wandelt der Wertkonverter auch zwischen den Quellentyp und den Zieltyp um. Dies ist nützlich, wenn die von execute () aufgerufene Anfrage von einem anderen Typ ist als das gewünschte Hintergrundfeld.
// 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 ( ) ;
}
}