2016-12-05 11 views
1

Я пытаюсь вставить 10000 записей в хранилище таблиц Azure. Я использую ExecuteAsync() для его достижения, но примерно примерно 7500 записей вставляются, а остальные записи теряются. Я намеренно не использую жду ключевое слово, потому что я не хочу ждать результата, просто хочу сохранить их в таблице. Ниже приведен фрагмент кода.ExecuteAsync() хранилища таблиц Azure, не вставляя все записи

private static async void ConfigureAzureStorageTable() 
    { 
     CloudStorageAccount storageAccount = 
      CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString")); 
     CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); 
     TableResult result = new TableResult(); 
     CloudTable table = tableClient.GetTableReference("test"); 
     table.CreateIfNotExists(); 

     for (int i = 0; i < 10000; i++) 
     { 
      var verifyVariableEntityObject = new VerifyVariableEntity() 
      { 
       ConsumerId = String.Format("{0}", i), 
       Score = String.Format("{0}", i * 2 + 2), 
       PartitionKey = String.Format("{0}", i), 
       RowKey = String.Format("{0}", i * 2 + 2) 
      }; 
      TableOperation insertOperation = TableOperation.Insert(verifyVariableEntityObject); 
      try 
      { 
       table.ExecuteAsync(insertOperation); 
      } 
      catch (Exception e) 
      { 

       Console.WriteLine(e.Message); 
      } 
     } 
    } 

Неправильно ли использование метода?

+1

Если вы не дождались завершения, оно может не закончиться (особенно если ваш процесс завершен). И вы не узнаете о каких-либо ошибках. – SLaks

+0

Если вы не дождались его завершения, это, вероятно, не закончится! – DavidG

+0

Вы решили эту проблему, какие-либо обновления? Вы можете поймать подробное исключение в своем консольном приложении и захватить сетевой пакет через Fiddler, когда вы вставляете записи в Azure Table Storage. –

ответ

3

Вы еще хотите await table.ExecuteAsync(). Это будет означать, что ConfigureAzureStorageTable() возвращает управление вызывающему абоненту в этой точке, который может продолжить выполнение.

Путь у вас есть в этом вопросе, ConfigureAzureStorageTable() собирается продолжить мимо вызова table.ExecuteAsync() и выхода, и такие вещи, как table будет выходить за рамки, в то время как table.ExecuteAsync() задача еще не завершена.

Существует много предостережений об использовании async void на SO и в других местах, которые вам также необходимо учитывать. Вы можете так же легко иметь свой метод как async Task, но не ждать его в вызывающем еще, но сохранить возвращенную Task вокруг чистого прекращения и т.д.

Редактировать: одно дополнение - вы почти наверняка хотите использовать ConfigureAwait(false) на вашем await там, поскольку вам, кажется, не нужно сохранять какой-либо контекст. У этого blog post есть некоторые рекомендации по этому вопросу и асинхронные вообще.

1

Как насчет использования TableBatchOperation для запуска партий N вставок сразу?

private const int BatchSize = 100; 

private static async void ConfigureAzureStorageTable() 
{ 
    CloudStorageAccount storageAccount = 
     CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString")); 
    CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); 
    TableResult result = new TableResult(); 
    CloudTable table = tableClient.GetTableReference("test"); 
    table.CreateIfNotExists(); 

    var batchOperation = new TableBatchOperation(); 

    for (int i = 0; i < 10000; i++) 
    { 
     var verifyVariableEntityObject = new VerifyVariableEntity() 
     { 
      ConsumerId = String.Format("{0}", i), 
      Score = String.Format("{0}", i * 2 + 2), 
      PartitionKey = String.Format("{0}", i), 
      RowKey = String.Format("{0}", i * 2 + 2) 
     }; 
     TableOperation insertOperation = TableOperation.Insert(verifyVariableEntityObject); 
     batchOperation.Add(insertOperation); 

     if (batchOperation.Count >= BatchSize) 
     { 
      try 
      { 
       await table.ExecuteBatchAsync(batchOperation); 
       batchOperation = new TableBatchOperation(); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.Message); 
      } 
     } 
    } 

    if(batchOperation.Count > 0) 
    { 
     try 
     { 
      await table.ExecuteBatchAsync(batchOperation); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
     } 
    } 
} 

Вы можете настроить BatchSize так, как вам нужно. Небольшой отказ от ответственности: я не пытался запустить это, хотя он должен работать.

Но я не могу не задаться вопросом, почему ваша функция async void? Это должно быть зарезервировано для обработчиков событий и подобных, где вы не можете решить интерфейс. В большинстве случаев вы хотите вернуть задачу. Потому что теперь вызывающий абонент не может перехватывать исключения, возникающие в этой функции.

0

async void не является хорошей практикой, если это не обработчик событий.

https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

Если вы планируете вставить много записей в лазурное хранение таблицы, пакетная вставка является лучшим выбором.

https://msdn.microsoft.com/en-us/library/azure/microsoft.windowsazure.storage.table.tablebatchoperation.aspx

Имейте в виду, что она имеет предел 100 операций таблицы в одной партии.

1

В соответствии с вашим требованием, я проверил ваш сценарий на моей стороне, успешно используя и CloudTable.ExecuteBatchAsync. Вот мой фрагмент кода об использовании CloudTable.ExecuteBatchAsync для вставки записей в Azure Table Storage, вы можете обратиться к нему.

Программа.CS Главная

class Program 
{ 
    static void Main(string[] args) 
    { 
     CloudStorageAccount storageAccount = 
      CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString")); 
     CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); 
     TableResult result = new TableResult(); 
     CloudTable table = tableClient.GetTableReference("test"); 
     table.CreateIfNotExists(); 

     //Generate records to be inserted into Azure Table Storage 
     var entities = Enumerable.Range(1, 10000).Select(i => new VerifyVariableEntity() 
     { 
      ConsumerId = String.Format("{0}", i), 
      Score = String.Format("{0}", i * 2 + 2), 
      PartitionKey = String.Format("{0}", i), 
      RowKey = String.Format("{0}", i * 2 + 2) 
     }); 

     //Group records by PartitionKey and prepare for executing batch operations 
     var batches = TableBatchHelper<VerifyVariableEntity>.GetBatches(entities); 

     //Execute batch operations in parallel 
     Parallel.ForEach(batches, new ParallelOptions() 
     { 
      MaxDegreeOfParallelism = 5 
     }, (batchOperation) => 
     { 
      try 
      { 
       table.ExecuteBatch(batchOperation); 
       Console.WriteLine("Writing {0} records", batchOperation.Count); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("ExecuteBatch throw a exception:" + ex.Message); 
      } 
     }); 
     Console.WriteLine("Done!"); 
     Console.WriteLine("Press any key to exit..."); 
     Console.ReadKey(); 
    } 
} 

TableBatchHelper.cs

public class TableBatchHelper<T> where T : ITableEntity 
{ 
    const int batchMaxSize = 100; 

    public static IEnumerable<TableBatchOperation> GetBatches(IEnumerable<T> items) 
    { 
     var list = new List<TableBatchOperation>(); 
     var partitionGroups = items.GroupBy(arg => arg.PartitionKey).ToArray(); 
     foreach (var group in partitionGroups) 
     { 
      T[] groupList = group.ToArray(); 
      int offSet = batchMaxSize; 
      T[] entities = groupList.Take(offSet).ToArray(); 
      while (entities.Any()) 
      { 
       var tableBatchOperation = new TableBatchOperation(); 
       foreach (var entity in entities) 
       { 
        tableBatchOperation.Add(TableOperation.InsertOrReplace(entity)); 
       } 
       list.Add(tableBatchOperation); 
       entities = groupList.Skip(offSet).Take(batchMaxSize).ToArray(); 
       offSet += batchMaxSize; 
      } 
     } 
     return list; 
    } 
} 

Примечание: Как было упомянуто в официальном document о вставке партии сущностей:

Одна операция партия может включают до enti связей.

Все объекты в одной пакетной операции должны иметь ту же клавишу раздела.

В целом, пожалуйста, постарайтесь проверить, может ли он работать на вашей стороне. Кроме того, вы можете зафиксировать подробное исключение в своем консольном приложении и захватить HTTP-запрос через Fiddler, чтобы поймать запросы HTTP-ошибок при вставке записей в Azure Table Storage.