Консольное приложение .NET 8 работает медленнее после публикацииC#

Место общения программистов C#
Ответить
Anonymous
 Консольное приложение .NET 8 работает медленнее после публикации

Сообщение Anonymous »

Я не понимаю, почему мое приложение работает медленнее, когда я запускаю его, выполняя файл .exe из папки публикации, по сравнению с запуском его из отладчика Visual Studio (F5).
Я использую .NET 8.0, и это мой код program.cs:

Код: Выделить всё

using System.Data;
using System.Diagnostics;

Console.WriteLine("Generating sample DataTable...");
var stopwatch = Stopwatch.StartNew();

DataTable table = GenerateLargeSampleTable(1_000_000, 100);

stopwatch.Stop();
Console.WriteLine($"DataTable generated in {stopwatch.Elapsed.TotalSeconds:F2} seconds.");
Console.ReadLine();

static DataTable GenerateLargeSampleTable(int rowCount, int columnCount)
{
var table = new DataTable("SampleData");

var rand = new Random();

for (int i = 0; i < columnCount; i++)
{
if (i % 3 == 0)
table.Columns.Add($"StringCol_{i}", typeof(string));
else if (i % 3 == 1)
table.Columns.Add($"NumberCol_{i}", typeof(double));
else
table.Columns.Add($"DateCol_{i}", typeof(DateTime));
}

table.BeginLoadData();

for (int r = 0; r < rowCount; r++)
{
var row = table.NewRow();

for (int c = 0; c < columnCount; c++)
{
switch (table.Columns[c].DataType.Name)
{
case nameof(String):
row[c] = $"Text_{r}_{c}";
break;

case nameof(Double):
row[c] = Math.Round(rand.NextDouble() * 10000, 2);
break;

case nameof(DateTime):
row[c] = DateTime.Now.AddDays(-rand.Next(0, 3650));
break;
}
}

table.Rows.Add(row);
}

table.EndLoadData();

return table;
}
Когда я запускаю его из Visual Studio, процесс занимает около 15 секунд:
Изображение

Но он занимает около 40 секунд при запуске из файла .exe после публикация:
Изображение

Это мой профиль публикации:
Изображение

Я думал, что запуск опубликованной версии должен быть быстрее, а не медленнее, поскольку не работают инструменты отладки. Может кто-нибудь сказать мне, что происходит?
Примечания: мое устройство работает под управлением Windows Home с процессором Intel Core i9 12-го поколения и 32 ГБ оперативной памяти. Я использую Visual Studio 2022.

Поскольку Марк считает, что DataTable — плохой выбор, я меняю код на более простой (добавляю строки в список). Я также создал более обширный журнал, как предложил Альпарсиан, и, поскольку подозреваю, что консоль может быть источником проблем с производительностью, я создаю класс AsyncLogger для асинхронной записи в консоль.
Это мой новый код program.cs:

Код: Выделить всё

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

for (int i = 0; i < 10; i++)
{
AsyncLogger.Log($"Generating sample data, rep: {i}...");
var totalWatch = Stopwatch.StartNew();

var data = GenerateLargeDynamicData(1_000_000, 1000);

totalWatch.Stop();
AsyncLogger.Log($"Data generated in {totalWatch.Elapsed.TotalSeconds:F2} seconds total.");
AsyncLogger.Log($"Total rows: {data.Count:N0}");

GC.Collect();
long mem = GC.GetTotalMemory(forceFullCollection: true);
AsyncLogger.Log($"Current memory usage: {mem / 1024 / 1024} MB");
}

// Wait for all log messages to complete
await AsyncLogger.FlushAsync();
Console.ReadLine();

static List GenerateLargeDynamicData(int rowCount, int columnCount)
{
AsyncLogger.Log($"[Start] Generating {rowCount:N0} strings of length {columnCount:N0}...");

var totalWatch = Stopwatch.StartNew();

var stepWatch = Stopwatch.StartNew();
List data = new List();
stepWatch.Stop();
AsyncLogger.Log($"[Timing] List initialized in {stepWatch.Elapsed.TotalMilliseconds:F3} ms");

stepWatch.Restart();

int batchSize = 100_000;
int batchCount = 0;
var batchWatch = Stopwatch.StartNew();

for (int i = 0; i < rowCount; i++)
{
data.Add(new string('X', columnCount));

if ((i + 1) % batchSize == 0)
{
batchCount++;
AsyncLogger.Log($"[Batch {batchCount}] Generated {i + 1:N0}/{rowCount:N0} items — " +
$"{batchWatch.Elapsed.TotalSeconds:F2}s elapsed " +
$"(avg {batchWatch.Elapsed.TotalMilliseconds / batchSize:F4} ms/item)");
batchWatch.Restart();
}
}

stepWatch.Stop();
AsyncLogger.Log($"[Timing] String generation: {stepWatch.Elapsed.TotalSeconds:F3}s");

totalWatch.Stop();
AsyncLogger.Log($"[Timing] Total execution time: {totalWatch.Elapsed.TotalSeconds:F3}s");

return data;
}

static class AsyncLogger
{
private static readonly BlockingCollection _logQueue = new();
private static readonly Task _loggingTask;

static AsyncLogger()
{
_loggingTask = Task.Run(async () =>
{
foreach (var msg in _logQueue.GetConsumingEnumerable())
{
await Console.Out.WriteLineAsync(msg);
}
});
}

public static void Log(string message)
{
// Don’t block — drop message if queue is too full
if (_logQueue.Count < 10_000)
_logQueue.Add(message);
}

public static async Task FlushAsync()
{
// Wait until all messages processed
_logQueue.CompleteAdding();
await _loggingTask;
}
}
Результат все еще другой.
Это результат отладки Visual Studio.
Изображение
И это результат исполняемого файла отладки (теперь я запускаю исполняемый файл из папки отладки, так как подозреваю, что опубликуйте, добавьте что-нибудь, что замедлит работу).
Изображение

Медленная часть не только в генерации данных цикла, но и инициализация списка также медленнее. Я подозреваю, что это вызвано распределением памяти.

Подробнее здесь: https://stackoverflow.com/questions/797 ... er-publish
Ответить

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

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

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

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

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