Прочитать на английском

Поделиться через


Потокобезопасность и управление жизненным циклом клиента для объектов пакета SDK Azure

Эта статья поможет вам понять проблемы с потокобезопасностью, возникающие при использовании пакета Azure SDK. В ней также обсуждается, как структура пакета SDK влияет на управление жизненным циклом клиента. Вы узнаете, почему не требуется освобождать клиентские объекты пакета SDK для Azure.

Потокобезопасность

Все клиентские объекты Azure SDK являются потокобезопасными и независимы друг от друга. Такая схема гарантирует неизменную надежность при повторном использовании экземпляров клиента даже в разных потоках. Например, следующий код запускает несколько задач, но является потокобезопасным:

C#
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));
}

Объекты входных и выходных моделей, используемые клиентами пакета SDK, не являются потокобезопасными по умолчанию. В большинстве вариантов использования с объектами моделей применяется только один поток. Поэтому затраты на реализацию синхронизации в качестве поведения по умолчанию для этих объектов слишком высоки. В следующем коде показана ошибка, при которой доступ к модели из нескольких потоков может привести к неопределенному поведению.

C#
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);

Для доступа к модели из разных потоков необходимо реализовать собственный код синхронизации. Например:

C#
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);

Время существования клиента

Поскольку клиенты пакета Azure SDK являются потокобезопасными, нет необходимости создавать несколько клиентских объектов SDK для заданного набора параметров конструктора. Рассматривайте созданные клиентские объекты пакета Azure SDK как элементы singleton. Эта рекомендация обычно реализуется путем регистрации клиентских объектов Azure SDK в качестве элементов singleton в контейнере инверсии управления (IoC) приложения. Для получения ссылок на клиентский объект SDK используется внедрение зависимостей (DI). В следующем примере показана регистрация одного клиентского объекта:

C#
var builder = Host.CreateApplicationBuilder(args);

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

builder.Services.AddSingleton(blobServiceClient);

Дополнительные сведения о реализации DI с помощью пакета Azure SDK см. в статье Внедрение зависимостей с помощью пакета Azure SDK для .NET.

Кроме того, вы можете создать клиентский экземпляр SDK и предоставить его методам, которым требуется клиент. Суть в том, чтобы избежать ненужных экземпляров одного и того же клиентского объекта SDK с теми же параметрами. Это бесполезно и неэффективно.

Отсутствие освобождения клиентов

Ниже приведены два последних наиболее часто задаваемых вопроса.

  • Нужно ли освобождать клиентские объекты пакета Azure SDK по завершении их использования?
  • Почему клиентские объекты пакета Azure SDK на основе HTTP не освобождаются?

На внутреннем уровне все клиенты Azure SDK используют один общий экземпляр HttpClient. Клиенты не создают никаких ресурсов, которые требуют активного освобождения. Общий экземпляр HttpClient сохраняется в течение всего времени существования приложения.

C#
// 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));

Клиентскому объекту Azure SDK можно предоставить пользовательский экземпляр HttpClient. В этом случае вы несете ответственность за управление жизненным циклом HttpClient и его правильное удаление в нужное время.

C#
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();

Дополнительные рекомендации по правильному управлению экземплярами HttpClient и их освобождению можно найти в документации HttpClient.

См. также