Пока я работал с относительно большими текстовыми файлами, я заметил нечто странное. Asyn c Чтение и запись на самом деле медленнее, чем не-asyn c чтение:
E, g, выполнение этого фиктивного кода:
var res1 = File.WriteAllLinesAsync(string.Format(@"C:\Projects\DelMee\file{0}.txt", i), lines);
var res2 = File.WriteAllLinesAsync(string.Format(@"C:\Projects\DelMee\file{0}_bck.txt", i), lines);
await res1;
await res2;
на самом деле намного медленнее, чем
File.WriteAllLines(string.Format(@"C:\Projects\DelMee\file{0}.txt", i), lines);
File.WriteAllLines(string.Format(@"C:\Projects\DelMee\file{0}_bck.txt", i), lines);
Теоретически первый подход должен быть более быстрым, потому что второе сочинение следует рассмотреть до завершения первого. Разница в производительности составляет около 100% для файлов размером 15 ~ 25 МБ (10 против 20 секунд).
Я заметил одинаковое поведение для ReadAllLines и ReadAllLinesAsyn c.
Обновление: 0 Основная идея состоит в том, чтобы все файлы обрабатывались после завершения функции Функции TestFileWriteXXX. Поэтому
Task.WhenAll(allTasks1); // Without await is not a valid option
Обновление: 1 Я добавил чтение и запись, используя потоки, и это показало улучшение на 50%. Вот полный пример:
Обновление: 2 Я обновил код, чтобы устранить накладные расходы на генерацию буфера
const int MaxAttempts = 5;
static void Main(string[] args)
{
TestFileWrite();
TestFileWriteViaThread();
TestFileWriteAsync();
Console.ReadLine();
}
private static void TestFileWrite()
{
Clear();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
Console.WriteLine( "Begin TestFileWrite");
for (int i = 0; i < MaxAttempts; ++i)
{
TestFileWriteInt(i);
}
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
Console.WriteLine("TestFileWrite took: " + elapsedTime);
}
private static void TestFileWriteViaThread()
{
Clear();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
Console.WriteLine("Begin TestFileWriteViaThread");
List<Thread> _threads = new List<Thread>();
for (int i = 0; i < MaxAttempts; ++i)
{
var t = new Thread(TestFileWriteInt);
t.Start(i);
_threads.Add(t);
}
_threads.ForEach(T => T.Join());
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
Console.WriteLine("TestFileWriteViaThread took: " + elapsedTime);
}
private static void TestFileWriteInt(object oIndex)
{
int index = (int)oIndex;
List<string> lines = GenerateLines(index);
File.WriteAllLines(string.Format(@"C:\Projects\DelMee\file{0}.txt", index), lines);
File.WriteAllLines(string.Format(@"F:\Projects\DelMee\file{0}_bck.txt", index), lines);
var text = File.ReadAllLines(string.Format(@"C:\Projects\DelMee\file{0}.txt", index));
var text1 = File.ReadAllLines(string.Format(@"C:\Projects\DelMee\file{0}.txt", index));
//File.WriteAllLines(string.Format(@"C:\Projects\DelMee\file_test{0}.txt", index), text1);
}
private static async void TestFileWriteAsync()
{
Clear();
Console.WriteLine("Begin TestFileWriteAsync ");
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
for (int i = 0; i < MaxAttempts; ++i)
{
List<string> lines = GenerateLines(i);
var allTasks = new List<Task>();
allTasks.Add(File.WriteAllLinesAsync(string.Format(@"C:\Projects\DelMee\file{0}.txt", i), lines));
allTasks.Add(File.WriteAllLinesAsync(string.Format(@"F:\Projects\DelMee\file{0}_bck.txt", i), lines));
await Task.WhenAll(allTasks);
var allTasks1 = new List<Task<string[]>>();
allTasks1.Add(File.ReadAllLinesAsync(string.Format(@"C:\Projects\DelMee\file{0}.txt", i)));
allTasks1.Add(File.ReadAllLinesAsync(string.Format(@"C:\Projects\DelMee\file{0}.txt", i)));
await Task.WhenAll(allTasks1);
// await File.WriteAllLinesAsync(string.Format(@"C:\Projects\DelMee\file_test{0}.txt", i), allTasks1[0].Result);
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
Console.WriteLine("TestFileWriteAsync took: " + elapsedTime);
}
private static void Clear()
{
for (int i = 0; i < 15; ++i)
{
System.IO.File.Delete(string.Format(@"C:\Projects\DelMee\file{0}.txt", i));
System.IO.File.Delete(string.Format(@"F:\Projects\DelMee\file{0}_bck.txt", i));
}
}
static string buffer = new string('a', 25 * 1024 * 1024);
private static List<string> GenerateLines(int i)
{
return new List<string>() { buffer };
}
И результаты:
TestFileWrite занимает: 00: 00: 03.50
TestFileWriteViaThread принимает: 00: 00: 01.63
TestFileWriteAsyn c принимает: 00: 00: 06.78
8 Код CPU / C и F - два разных SSD-накопителя 850 EVO на двух разных SATA.
Обновление: 3 - Заключение Похоже, File.WriteAllLinesAsyn c хорошо справляется со сценарием когда мы хотим грипп sh большой объем данных. Как указывалось в ответах ниже, лучше использовать FileStream напрямую. Но асинхронный c все же медленнее, чем последовательный доступ.
Но пока самый быстрый подход остается, если вы используете многопоточность.