#c# #asynchronous #async-await
#c# #асинхронный #асинхронное ожидание
Вопрос:
Мне нужна помощь в отношении асинхронного программирования. Для простоты рассмотрим список целых чисел 2, 1, 3, 3, 4, 5
У меня есть две асинхронные задачи. Одна для получения записи, а другая для создания записи. Я хочу создать запись только в том случае, если свойство id еще не существует.
public async Task<Record> GetRecord(int id)
{
var client = new HttpClient();
// build request
// var response = await client.SendAsync(request); // sending to 3rd party vendor
// depending on response, return the Record object or null
}
public async Task<bool> CreateRecord(int id)
{
var client = new HttpClient();
// build request
// var response = await client.SendAsync(request); // sending to 3rd party vendor
// depending on response, return true or false
}
Основная программа
foreach(var id in IDs)
{
var record = await GetRecord(id); ?? How can I wait here
if (record == null)
await CreateRecord(id)
}
По какой-то причине эта программа создает записи с 2, 1, 3, 3, 4, 5. Это не должно создавать дублирующуюся запись с идентификатором 3.
Я также попробовал следующее, но это также создает повторяющиеся записи
var record = Task.Run( async => await GetRecord(id)).Result
Любая помощь будет принята с благодарностью.
Комментарии:
1.хм, одна вещь, которая может прийти мне в голову, — это ограничение потоков, использующих
SemaphoreSlim
docs.microsoft.com/en-us/dotnet/api /…2. конечно, есть и другой вариант, например, использование подхода Then Recursion.
3. Основываясь на опубликованном вами коде, ваша программа должна работать должным образом. Не могли бы вы предложить воспроизводимый пример? Кстати, пожалуйста, взгляните на это руководство относительно использования
HttpClient
класса.4. Хм … ваш код выглядит нормально таким, какой он есть. Может быть что-то конкретное в вашем вызове GetRecord, где бы он ни был реализован. Возможно, он возвращает null, когда уже существует существующая запись с заданным идентификатором.
Ответ №1:
Вот пример, который я попытался показать, что у вас должно работать нормально.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace TestSync
{
public class Record
{
public int Id { get; set; }
public Record(int id)
{
this.Id = id;
}
}
public class TestClass
{
private List<Record> SavedRecords = new List<Record>();
private List<int> Ids = new List<int>{1, 2, 1, 3, 3, 4, 5, 3, 3, 4, 4, 2, 2};
private Random randome = new Random(8383838);
public async Task Process()
{
foreach (var id in Ids)
{
var record = await GetRecord(id);
if (record == null)
await CreateRecord(id);
}
}
public async Task<Record> GetRecord(int id)
{
await Task.Delay(randome.Next(100, 200));// simulate delay for a HttpClient kind of call
return SavedRecords.FirstOrDefault(i => i.Id == id);
}
public async Task<bool> CreateRecord(int id)
{
await Task.Delay(randome.Next(200, 500));// simulate delay for a HttpClient kind of call
SavedRecords.Add(new Record(id));
return true;
}
public void Print()
{
foreach (var record in SavedRecords)
Console.WriteLine(record.Id);
}
}
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Creating records!");
var t = new TestClass();
await t.Process();
t.Print();
Console.WriteLine("Done creating records!");
Console.ReadKey();
}
}
}
Комментарии:
1. Привет, Атаду, большое вам спасибо за ваше решение. Я попытался использовать строку случайной задержки из вашего кода, и, похоже, она работает. Так что, возможно, сторонней системе требуется время для фактического создания записи.