Увеличение производительности асинхронного Parallel.Foreach - PullRequest
0 голосов
/ 15 марта 2019

У меня в списке устройств более 10 тыс. Элементов, и я хочу отправить данные, вызвав другой метод.

Я пытался использовать Parallel.Foreach, но я не уверен, что это правильный способ сделать это.

Я опубликовал это веб-приложение на Azure, я проверил его на 100, он работает нормально, но на 10k он получил проблему тайм-аута. Моя реализация нуждается в настройке, спасибо

private List<Task> taskEventList = new List<Task>();
public async Task ProcessStart()
{
    string messageData = "{\"name\":\"DemoData\",\"no\":\"111\"}";
    RegistryManager registryManager;

    Parallel.ForEach(deviceList, async (device) =>
    {
        // get details for each device and use key to send message
        device = await registryManager.GetDeviceAsync(device.DeviceId);
        SendMessages(device.DeviceId, device.Key, messageData);
    });

    if (taskEventList.Count > 0)
    {
        await Task.WhenAll(taskEventList);
    }
}

private void SendMessages(string deviceId, string Key, string messageData)
{
    DeviceClient deviceClient = DeviceClient.Create(hostName, new DeviceAuthenticationWithRegistrySymmetricKey(deviceId, deviceKey), Microsoft.Azure.Devices.Client.TransportType.Mqtt);
    //created separate Task
    var taskEvents = Task.Run(() => ProcessMessages(deviceId, string messageData));
    taskEventList.Add(taskEvents);
}

private async Task ProcessMessages(string deviceId, string messageData)
{
    var startTime = DateTime.UtcNow;
    while (DateTime.UtcNow - startTime < TimeSpan.FromMinutes(15))
    {
        await deviceClient.SendEventAsync(messageData);
    }
}

1 Ответ

4 голосов
/ 15 марта 2019

По крайней мере, есть определенное состояние гонки. Parallel - только для синхронного кода, не асинхронный.

Насколько я вижу, вам не нужны Parallel или Task.Run (которые оба являются антипаттернами для служб ASP.NET):

public async Task ProcessStart()
{
  string messageData = "{\"name\":\"DemoData\",\"no\":\"111\"}";
  RegistryManager registryManager;

  var tasks = deviceList.Select(async device =>
  {
    // get details for each device and use key to send message
    device = await registryManager.GetDeviceAsync(device.DeviceId);
    await SendMessagesAsync(device.DeviceId, device.Key, messageData);
  }).ToList();

  await Task.WhenAll(tasks);
}

private async Task SendMessagesAsync(string deviceId, string Key, string messageData)
{
  DeviceClient deviceClient = DeviceClient.Create(hostName, new DeviceAuthenticationWithRegistrySymmetricKey(deviceId, deviceKey), Microsoft.Azure.Devices.Client.TransportType.Mqtt);
  await ProcessMessagesAsync(deviceId, string messageData);
}

private async Task ProcessMessagesAsync(string deviceId, string messageData)
{
  var startTime = DateTime.UtcNow;
  while (DateTime.UtcNow - startTime < TimeSpan.FromMinutes(15))
  {
    await deviceClient.SendEventAsync(messageData);
  }
}

для 10k получен тайм-аут.

15 минут - это long время для HTTP-запроса. Я думаю, что стоило бы сделать шаг назад и посмотреть, есть ли лучший способ для проектирования всей системы.

...