Как только вы окажетесь на LINQ, вы находитесь на милость своих счетчиков и сборщиков мусора.
Если вы хотите выжать максимум производительности, насколько это возможно из ваших foreach
петель и у вас есть контроль над структурами данных, убедитесь, что вы используете типы коллекций, которые имеют структуры счетчиков (т.е. List<T>
, ImmutableArray<T>
). Еще лучше, если это возможно, используйте простые общие массивы. Несмотря на неструктурный перечислитель, они являются самым быстрым типом коллекции в .NET, когда дело доходит до необработанной скорости доступа, по крайней мере, при создании в Release/с включенными оптимизациями (в этом случае компилятор испускает один и тот же IL для ваших циклов по массивам как это было бы для циклов for
, тем самым сокращая ассигнования и вызовы методов, обычно связанные с использованием типов, которые реализуют IEnumerable<T>
).
Рослин имеет set of guidelines для горячих путей кода, которые полезны в вашей ситуации:
- Избегайте LINQ.
- Избегайте использования foreach над коллекциями, которые не имеют перечислителя структуры.
Теперь приведенное выше действие действительно в любом критическом сценарии. Тем не менее, я скептически отношусь к тому, что производительность итераций сборов является узким местом в вашей конкретной ситуации. Скорее всего, DoSomeWork
занимает больше времени, чем вам хотелось бы. Вы должны прокомментировать ваш вызов GenerateRecords
, чтобы получить окончательный ответ о том, какие биты кода требуют наибольшего внимания.
Если вы уверены, что ваша реализация DoSomeWork
оптимальна, рассмотрите возможность параллелизации вашей рабочей нагрузки.
При условии, что ваш DoSomeWork
реализация является чистой и не зависит от внешних изменяемых состояний (то есть переменный класс), вы можете быть в состоянии parallelise некоторые из ваших итераций цикла через Parallel.For
или Parallel.ForEach
. Ваш внешний контур выглядит для него особенно хорошим кандидатом, но вам, возможно, придется поиграть с размещением параллельного цикла, пока не получите желаемые характеристики производительности. В качестве отправной точки, вот что я бы рекомендовал:
private void GenerateRecords(JobRequest request)
{
Parallel.For(0, daysInRange, day =>
{
foreach (var coreId in request.CoreIds)
{
for (var i = 0; i < request.AgentsCount; i++)
{
var agentId = Guid.NewGuid();
for (var copiesDone = 0; copiesDone < request.CopiesToMake; copiesDone++)
{
foreach (var jobInfoRecord in request.Jobs)
{
foreach (var status in request.Statuses)
{
//DoSomeWork();
}
}
}
}
}
});
}
Зависит, что вы делаете со значениями каждого 'foreach'? –
Ничего, просто создавайте новые объекты – Anatoly
Если проблема связана с петлями, вы можете попробовать использовать разворот цикла. Или у вас всегда есть возможность использовать потоки. – Carra