Dela via


Trådsäkerhet och klientlivslängdshantering för Azure SDK-objekt

Den här artikeln hjälper dig att förstå trådsäkerhetsproblem när du använder Azure SDK. Den beskriver också hur SDK:s utformning påverkar klientens livslängdshantering. Du får lära dig varför det inte är nödvändigt att ta bort Azure SDK-klientobjekt.

Trådsäkerhet

Alla Azure SDK-klientobjekt är trådsäkra och oberoende av varandra. Den här designen säkerställer att återanvändning av klientinstanser alltid är säker, även över trådar. Följande kod startar till exempel flera uppgifter men är trådsäker:

var client = new SecretClient(
    new Uri("<secrets_endpoint>"), new DefaultAzureCredential());

foreach (var secretName in secretNames)
{
    // Using clients from parallel threads
    Task.Run(() => Console.WriteLine(client.GetSecret(secretName).Value));
}

Modellobjekt som används av SDK-klienter, oavsett om de är indata- eller utdatamodeller, är inte trådsäkra som standard. De flesta användningsfall som rör modellobjekt använder bara en enda tråd. Därför är kostnaden för att implementera synkronisering som standardbeteende för höga för dessa objekt. Följande kod illustrerar ett fel där åtkomst till en modell från flera trådar kan orsaka ett odefinierat beteende:

KeyVaultSecret newSecret = client.SetSecret("secret", "value");

foreach (var tag in tags)
{
    // Don't use model type from parallel threads
    Task.Run(() => newSecret.Properties.Tags[tag] = CalculateTagValue(tag));
}

client.UpdateSecretProperties(newSecret.Properties);

Om du vill komma åt modellen från olika trådar måste du implementera din egen synkroniseringskod. Till exempel:

KeyVaultSecret newSecret = client.SetSecret("secret", "value");

// Code omitted for brevity

foreach (var tag in tags)
{
    Task.Run(() =>
    {
        lock (newSecret)
        {
            newSecret.Properties.Tags[tag] = CalculateTagValue(tag);
        }
    );
}

client.UpdateSecretProperties(newSecret.Properties);

Klientlivslängd

Eftersom Azure SDK-klienter är trådsäkra finns det ingen anledning att konstruera flera SDK-klientobjekt för en viss uppsättning konstruktorparametrar. Behandla Azure SDK-klientobjekt som singletons när de har skapats. Den här rekommendationen implementeras ofta genom registrering av Azure SDK-klientobjekt som singletons i appens IoC-container (Inversion of Control). Beroendeinmatning (DI) används för att hämta referenser till SDK-klientobjektet. I följande exempel visas en registrering av singleton-klientobjekt:

var builder = Host.CreateApplicationBuilder(args);

var endpoint = builder.Configuration["SecretsEndpoint"];
var blobServiceClient = new BlobServiceClient(
    new Uri(endpoint), new DefaultAzureCredential());

builder.Services.AddSingleton(blobServiceClient);

Mer information om hur du implementerar DI med Azure SDK finns i Beroendeinmatning med Azure SDK för .NET.

Du kan också skapa en SDK-klientinstans och tillhandahålla den till metoder som kräver en klient. Poängen är att undvika onödiga instansieringar av samma SDK-klientobjekt med samma parametrar. Det är både onödigt och slösaktigt.

Klienter är inte disponibla

Två sista frågor som ofta kommer upp är:

  • Behöver jag ta bort Azure SDK-klientobjekt när jag är klar med att använda dem?
  • Varför är inte HTTP-baserade Azure SDK-klientobjekt disponibla?

Internt använder alla Azure SDK-klienter en enda delad HttpClient instans. Klienterna skapar inga andra resurser som aktivt behöver frigöras. Den delade HttpClient instansen finns kvar under hela programlivslängden.

// Both clients reuse the shared HttpClient and don't need to be disposed
var blobClient = new BlobClient(new Uri(sasUri));
var blobClient2 = new BlobClient(new Uri(sasUri2));

Det är möjligt att tillhandahålla en anpassad instans av HttpClient till ett Azure SDK-klientobjekt. I det här fallet blir du ansvarig för att hantera livslängden HttpClient och korrekt bortskaffa den vid rätt tidpunkt.

var httpClient = new HttpClient();

var clientOptions = new BlobClientOptions()
{
    Transport = new HttpClientTransport(httpClient)
};

// Both clients would use the HttpClient instance provided in clientOptions
var blobClient = new BlobClient(new Uri(sasUri), clientOptions);
var blobClient2 = new BlobClient(new Uri(sasUri2), clientOptions);

// Code omitted for brevity

// You're responsible for properly disposing httpClient some time later
httpClient.Dispose();

Ytterligare vägledning för korrekt hantering och bortskaffande av HttpClient instanser finns i dokumentationen HttpClient .

Se även