Многопоточность в цикле foreachC#

Место общения программистов C#
Ответить
Anonymous
 Многопоточность в цикле foreach

Сообщение Anonymous »

Я прочитал несколько тем stackoverflow о многопоточности в цикле foreach, но не уверен, что правильно понимаю и правильно ее использую.

Я пробовал несколько сценариев, но это не так. наблюдая значительное увеличение производительности.

Вот что, по моему мнению, запускает асинхронные задачи, но выполняется синхронно в цикле с использованием одного потока:< /p>

Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();

foreach (IExchangeAPI selectedApi in selectedApis)
{
if (exchangeSymbols.TryGetValue(selectedApi.Name, out symbol))
{
ticker = await selectedApi.GetTickerAsync(symbol);
}
}
stopWatch.Stop();


Вот то, на что я надеялся работать асинхронно (все еще используя один поток) – я ожидал некоторое улучшение скорости уже здесь:

List exchTkrs = new List();
stopWatch.Start();

foreach (IExchangeAPI selectedApi in selectedApis)
{
if (exchangeSymbols.TryGetValue(selectedApi.Name, out symbol))
{
exchTkrs.Add(selectedApi.GetTickerAsync(symbol));
}
}

ExchangeTicker[] retTickers = await Task.WhenAll(exchTkrs);
stopWatch.Stop();


Вот что я хотел бы запустить асинхронно в многопоточном режиме:

stopWatch.Start();

Parallel.ForEach(selectedApis, async (IExchangeAPI selectedApi) =>
{
if (exchangeSymbols.TryGetValue(selectedApi.Name, out symbol))
{
ticker = await selectedApi.GetTickerAsync(symbol);
}
});
stopWatch.Stop();


Результаты секундомера интерпретируются следующим образом:

Console.WriteLine("Time elapsed (ns): {0}", stopWatch.Elapsed.TotalMilliseconds * 1000000);


Выводы консоли:

Time elapsed (ns): 4183308100
Time elapsed (ns): 4183946299.9999995
Time elapsed (ns): 4188032599.9999995


Теперь улучшение скорости выглядит незначительным. Я делаю что-то не так или это более или менее то, чего мне следует ожидать? Полагаю, лучше это проверить при записи в файлы.

Не могли бы вы также подтвердить, что я правильно интерпретирую различные варианты использования?

Наконец, использование цикла foreach для параллельного получения тикера с нескольких платформ может быть не лучшим подходом. Будем рады предложениям по улучшению.

РЕДАКТИРОВАТЬ

Обратите внимание, что я использую базу кода ExchangeSharp. который вы можете найти здесь

Вот как выглядит метод GerTickerAsync():

public virtual async Task GetTickerAsync(string marketSymbol)
{
marketSymbol = NormalizeMarketSymbol(marketSymbol);
return await Cache.CacheMethod(MethodCachePolicy, async () => await OnGetTickerAsync(marketSymbol), nameof(GetTickerAsync), nameof(marketSymbol), marketSymbol);
}


Для API Kraken у вас есть:

protected override async Task OnGetTickerAsync(string marketSymbol)
{
JToken apiTickers = await MakeJsonRequestAsync("/0/public/Ticker", null, new Dictionary { { "pair", NormalizeMarketSymbol(marketSymbol) } });
JToken ticker = apiTickers[marketSymbol];
return await ConvertToExchangeTickerAsync(marketSymbol, ticker);
}


И метод кэширования:

public static async Task CacheMethod(this ICache cache, Dictionary methodCachePolicy, Func method, params object?[] arguments) where T : class
{
await new SynchronizationContextRemover();
methodCachePolicy.ThrowIfNull(nameof(methodCachePolicy));
if (arguments.Length % 2 == 0)
{
throw new ArgumentException("Must pass function name and then name and value of each argument");
}
string methodName = (arguments[0] ?? string.Empty).ToStringInvariant();
string cacheKey = methodName;
for (int i = 1; i < arguments.Length;)
{
cacheKey += "|" + (arguments[i++] ?? string.Empty).ToStringInvariant() + "=" + (arguments[i++] ?? string.Empty).ToStringInvariant("(null)");
}
if (methodCachePolicy.TryGetValue(methodName, out TimeSpan cacheTime))
{
return (await cache.Get(cacheKey, async () =>
{
T innerResult = await method();
return new CachedItem(innerResult, CryptoUtility.UtcNow.Add(cacheTime));
})).Value;
}
else
{
return await method();
}
}


Подробнее здесь: https://stackoverflow.com/questions/615 ... reach-loop
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»