StorageFile в 50 раз медленнее, чем IsolatedStorageFile

Я просто тестировал несколько алгоритмов, чтобы найти самый быстрый способ загрузки всех данных в мое приложение, когда обнаружил, что версия моего приложения WP7, работающая на Lumia 920, загружает данные в 2 раза быстрее, чем версия WP8, работающая на том же устройстве.

Затем я написал следующий независимый код для тестирования производительности StorageFile из WP8 и IsolatedStorageFile из WP7.

Чтобы уточнить заголовок, вот мои предварительные результаты тестов, которые я сделал, прочитав 50 файлов по 20 КБ и 100 КБ:

Код см. Ниже

Обновить

После нескольких часов тестов и интересных результатов позвольте мне перефразировать мои вопросы:

Почемуawait StreamReader.ReadToEndAsync() последовательно медленнее в каждом тесте, чем не асинхронный методStreamReader.ReadToEnd()? (На это уже может быть ответ в комментарии Нила Тернера)

Кажется, что при открытии файла с StorageFile возникают большие издержки, но только когда он открывается в потоке пользовательского интерфейса. (См. Разницу во времени загрузки между методом 1 и 3 или между 5 и 6, где 3 и 6 примерно в 10 раз быстрее, чем эквивалентный метод потока пользовательского интерфейса)

Есть ли другие способы чтения файлов, которые могут быть быстрее?

Обновление 3

Что ж, теперь с этим обновлением я добавил еще 10 алгоритмов, переназначая каждый алгоритм с каждым ранее использованным размером файла и количеством используемых файлов. На этот раз каждый алгоритм был запущен 10 раз. Таким образом, необработанные данные в файле Excel являются средним значением этих прогонов. Поскольку теперь существует 18 алгоритмов, каждый из которых протестирован с 4 размерами файлов (1 КБ, 20 КБ, 100 КБ, 1 МБ) для 50, 100 и 200 файлов каждый (18 * 4 * 3 = 216), было проведено 2160 тестов производительности, занимает общее время 95 минут (сырое время работы).

Обновление 5

Добавлены тесты 25, 26, 27 иReadStorageFile метод. Пришлось удалить какой-то текст, потому что в посте было более 30000 символов, что, видимо, максимум. Обновлен файл Excel с новыми данными, новой структурой, сравнениями и новыми графиками.

Код:

public async Task b1LoadDataStorageFileAsync()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");
    //b1 
    for (int i = 0; i < filepaths.Count; i++)
    {
        StorageFile f = await data.GetFileAsync(filepaths[i]);
        using (var stream = await f.OpenStreamForReadAsync())
        {
            using (StreamReader r = new StreamReader(stream))
            {
                filecontent = await r.ReadToEndAsync();
            }
        }
    }
}
public async Task b2LoadDataIsolatedStorage()
{
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        for (int i = 0; i < filepaths.Count; i++)
        {
            using (var stream = new IsolatedStorageFileStream("/benchmarks/samplefiles/" + filepaths[i], FileMode.Open, store))
            {
                using (StreamReader r = new StreamReader(stream))
                {
                    filecontent = r.ReadToEnd();
                }
            }
        }
    }
    await TaskEx.Delay(0);
}

public async Task b3LoadDataStorageFileAsyncThread()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");

    await await Task.Factory.StartNew(async () =>
    {
        for (int i = 0; i < filepaths.Count; i++)
        {

            StorageFile f = await data.GetFileAsync(filepaths[i]);
            using (var stream = await f.OpenStreamForReadAsync())
            {
                using (StreamReader r = new StreamReader(stream))
                {
                    filecontent = await r.ReadToEndAsync();
                }
            }
        }
    });
}
public async Task b4LoadDataStorageFileThread()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");

    await await Task.Factory.StartNew(async () =>
    {
        for (int i = 0; i < filepaths.Count; i++)
        {

            StorageFile f = await data.GetFileAsync(filepaths[i]);
            using (var stream = await f.OpenStreamForReadAsync())
            {
                using (StreamReader r = new StreamReader(stream))
                {
                    filecontent = r.ReadToEnd();
                }
            }
        }
    });
}
public async Task b5LoadDataStorageFile()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");
    //b5
    for (int i = 0; i < filepaths.Count; i++)
    {
        StorageFile f = await data.GetFileAsync(filepaths[i]);
        using (var stream = await f.OpenStreamForReadAsync())
        {
            using (StreamReader r = new StreamReader(stream))
            {
                filecontent = r.ReadToEnd();
            }
        }
    }
}
public async Task b6LoadDataIsolatedStorageThread()
{
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        await Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < filepaths.Count; i++)
                {
                    using (var stream = new IsolatedStorageFileStream("/benchmarks/samplefiles/" + filepaths[i], FileMode.Open, store))
                    {
                        using (StreamReader r = new StreamReader(stream))
                        {
                            filecontent = r.ReadToEnd();
                        }
                    }
                }
            });
    }
}
public async Task b7LoadDataIsolatedStorageAsync()
{
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        for (int i = 0; i < filepaths.Count; i++)
        {
            using (var stream = new IsolatedStorageFileStream("/benchmarks/samplefiles/" + filepaths[i], FileMode.Open, store))
            {
                using (StreamReader r = new StreamReader(stream))
                {
                    filecontent = await r.ReadToEndAsync();
                }
            }
        }
    }
}
public async Task b8LoadDataIsolatedStorageAsyncThread()
{
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        await await Task.Factory.StartNew(async () =>
        {
            for (int i = 0; i < filepaths.Count; i++)
            {
                using (var stream = new IsolatedStorageFileStream("/benchmarks/samplefiles/" + filepaths[i], FileMode.Open, store))
                {
                    using (StreamReader r = new StreamReader(stream))
                    {
                        filecontent = await r.ReadToEndAsync();
                    }
                }
            }
        });
    }
}


public async Task b9LoadDataStorageFileAsyncMy9()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");

    for (int i = 0; i < filepaths.Count; i++)
    {
        StorageFile f = await data.GetFileAsync(filepaths[i]);
        using (var stream = await f.OpenStreamForReadAsync())
        {
            using (StreamReader r = new StreamReader(stream))
            {
                filecontent = await Task.Factory.StartNew<String>(() => { return r.ReadToEnd(); });
            }
        }
    }
}

public async Task b10LoadDataIsolatedStorageAsyncMy10()
{
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        //b10
        for (int i = 0; i < filepaths.Count; i++)
        {
            using (var stream = new IsolatedStorageFileStream("/benchmarks/samplefiles/" + filepaths[i], FileMode.Open, store))
            {
                using (StreamReader r = new StreamReader(stream))
                {
                    filecontent = await Task.Factory.StartNew<String>(() => { return r.ReadToEnd(); });
                }
            }
        }
    }
}
public async Task b11LoadDataStorageFileAsyncMy11()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");

    for (int i = 0; i < filepaths.Count; i++)
    {
        await await Task.Factory.StartNew(async () =>
            {
                StorageFile f = await data.GetFileAsync(filepaths[i]);
                using (var stream = await f.OpenStreamForReadAsync())
                {
                    using (StreamReader r = new StreamReader(stream))
                    {
                        filecontent = r.ReadToEnd();
                    }
                }
            });
    }
}

public async Task b12LoadDataIsolatedStorageMy12()
{
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        for (int i = 0; i < filepaths.Count; i++)
        {
            await Task.Factory.StartNew(() =>
                {
                    using (var stream = new IsolatedStorageFileStream("/benchmarks/samplefiles/" + filepaths[i], FileMode.Open, store))
                    {
                        using (StreamReader r = new StreamReader(stream))
                        {
                            filecontent = r.ReadToEnd();
                        }
                    }
                });
        }
    }
}

public async Task b13LoadDataStorageFileParallel13()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");
    List<Task> tasks = new List<Task>();
    for (int i = 0; i < filepaths.Count; i++)
    {
        int index = i;
        var task = await Task.Factory.StartNew(async () =>
        {
            StorageFile f = await data.GetFileAsync(filepaths[index]);
            using (var stream = await f.OpenStreamForReadAsync())
            {
                using (StreamReader r = new StreamReader(stream))
                {
                    String content = r.ReadToEnd();
                    if (content.Length == 0)
                    {
                        //just some code to ensure this is not removed by optimization from the compiler
                        //because "content" is not used otherwise
                        //should never be called
                        ShowNotificationText(content);
                    }
                }
            }
        });
        tasks.Add(task);
    }
    await TaskEx.WhenAll(tasks);
}

public async Task b14LoadDataIsolatedStorageParallel14()
{
    List<Task> tasks = new List<Task>();
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        for (int i = 0; i < filepaths.Count; i++)
        {
            int index = i;
            var t = Task.Factory.StartNew(() =>
            {
                using (var stream = new IsolatedStorageFileStream("/benchmarks/samplefiles/" + filepaths[index], FileMode.Open, store))
                {
                    using (StreamReader r = new StreamReader(stream))
                    {
                        String content = r.ReadToEnd();
                        if (content.Length == 0)
                        {
                            //just some code to ensure this is not removed by optimization from the compiler
                            //because "content" is not used otherwise
                            //should never be called
                            ShowNotificationText(content);
                        }
                    }
                }
            });
            tasks.Add(t);
        }
        await TaskEx.WhenAll(tasks);
    }
}

public async Task b15LoadDataStorageFileParallelThread15()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");

    await await Task.Factory.StartNew(async () =>
        {
            List<Task> tasks = new List<Task>();
            for (int i = 0; i < filepaths.Count; i++)
            {
                int index = i;
                var task = await Task.Factory.StartNew(async () =>
                {
                    StorageFile f = await data.GetFileAsync(filepaths[index]);
                    using (var stream = await f.OpenStreamForReadAsync())
                    {
                        using (StreamReader r = new StreamReader(stream))
                        {
                            String content = r.ReadToEnd();
                            if (content.Length == 0)
                            {
                                //just some code to ensure this is not removed by optimization from the compiler
                                //because "content" is not used otherwise
                                //should never be called
                                ShowNotificationText(content);
                            }
                        }
                    }
                });
                tasks.Add(task);
            }
            await TaskEx.WhenAll(tasks);
        });
}

public async Task b16LoadDataIsolatedStorageParallelThread16()
{
    await await Task.Factory.StartNew(async () =>
        {
            List<Task> tasks = new List<Task>();
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                for (int i = 0; i < filepaths.Count; i++)
                {
                    int index = i;
                    var t = Task.Factory.StartNew(() =>
                    {
                        using (var stream = new IsolatedStorageFileStream("/benchmarks/samplefiles/" + filepaths[index], FileMode.Open, store))
                        {
                            using (StreamReader r = new StreamReader(stream))
                            {
                                String content = r.ReadToEnd();
                                if (content.Length == 0)
                                {
                                    //just some code to ensure this is not removed by optimization from the compiler
                                    //because "content" is not used otherwise
                                    //should never be called
                                    ShowNotificationText(content);
                                }
                            }
                        }
                    });
                    tasks.Add(t);
                }
                await TaskEx.WhenAll(tasks);
            }
        });
}
public async Task b17LoadDataStorageFileParallel17()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");
    List<Task<Task>> tasks = new List<Task<Task>>();
    for (int i = 0; i < filepaths.Count; i++)
    {
        int index = i;
        var task = Task.Factory.StartNew<Task>(async () =>
        {
            StorageFile f = await data.GetFileAsync(filepaths[index]);
            using (var stream = await f.OpenStreamForReadAsync())
            {
                using (StreamReader r = new StreamReader(stream))
                {
                    String content = r.ReadToEnd();
                    if (content.Length == 0)
                    {
                        //just some code to ensure this is not removed by optimization from the compiler
                        //because "content" is not used otherwise
                        //should never be called
                        ShowNotificationText(content);
                    }
                }
            }
        });
        tasks.Add(task);
    }
    await TaskEx.WhenAll(tasks);
    List<Task> tasks2 = new List<Task>();
    foreach (var item in tasks)
    {
        tasks2.Add(item.Result);
    }
    await TaskEx.WhenAll(tasks2);
}

public async Task b18LoadDataStorageFileParallelThread18()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");

    await await Task.Factory.StartNew(async () =>
    {
        List<Task<Task>> tasks = new List<Task<Task>>();
        for (int i = 0; i < filepaths.Count; i++)
        {
            int index = i;
            var task = Task.Factory.StartNew<Task>(async () =>
            {
                StorageFile f = await data.GetFileAsync(filepaths[index]);
                using (var stream = await f.OpenStreamForReadAsync())
                {
                    using (StreamReader r = new StreamReader(stream))
                    {
                        String content = r.ReadToEnd();
                        if (content.Length == 0)
                        {
                            //just some code to ensure this is not removed by optimization from the compiler
                            //because "content" is not used otherwise
                            //should never be called
                            ShowNotificationText(content);
                        }
                    }
                }
            });
            tasks.Add(task);
        }
        await TaskEx.WhenAll(tasks);
        List<Task> tasks2 = new List<Task>();
        foreach (var item in tasks)
        {
            tasks2.Add(item.Result);
        }
        await TaskEx.WhenAll(tasks2);
    });
}
public async Task b19LoadDataIsolatedStorageAsyncMyThread()
{
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        //b19
        await await Task.Factory.StartNew(async () =>
        {
            for (int i = 0; i < filepaths.Count; i++)
            {
                using (var stream = new IsolatedStorageFileStream("/benchmarks/samplefiles/" + filepaths[i], FileMode.Open, store))
                {
                    using (StreamReader r = new StreamReader(stream))
                    {
                        filecontent = await Task.Factory.StartNew<String>(() => { return r.ReadToEnd(); });
                    }
                }
            }
        });
    }
}

public async Task b20LoadDataIsolatedStorageAsyncMyConfigure()
{
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        for (int i = 0; i < filepaths.Count; i++)
        {
            using (var stream = new IsolatedStorageFileStream("/benchmarks/samplefiles/" + filepaths[i], FileMode.Open, store))
            {
                using (StreamReader r = new StreamReader(stream))
                {
                    filecontent = await Task.Factory.StartNew<String>(() => { return r.ReadToEnd(); }).ConfigureAwait(false);
                }
            }
        }
    }
}
public async Task b21LoadDataIsolatedStorageAsyncMyThreadConfigure()
{
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        await await Task.Factory.StartNew(async () =>
        {
            for (int i = 0; i < filepaths.Count; i++)
            {
                using (var stream = new IsolatedStorageFileStream("/benchmarks/samplefiles/" + filepaths[i], FileMode.Open, store))
                {
                    using (StreamReader r = new StreamReader(stream))
                    {
                        filecontent = await Task.Factory.StartNew<String>(() => { return r.ReadToEnd(); }).ConfigureAwait(false);
                    }
                }
            }
        });
    }
}
public async Task b22LoadDataOwnReadFileMethod()
{
    await await Task.Factory.StartNew(async () =>
    {
        for (int i = 0; i < filepaths.Count; i++)
        {
            filecontent = await ReadFile("/benchmarks/samplefiles/" + filepaths[i]);

        }
    });

}
public async Task b23LoadDataOwnReadFileMethodParallel()
{
    List<Task> tasks = new List<Task>();

    for (int i = 0; i < filepaths.Count; i++)
    {
        int index = i;
        var t = ReadFile("/benchmarks/samplefiles/" + filepaths[i]);
        tasks.Add(t);
    }
    await TaskEx.WhenAll(tasks);

}
public async Task b24LoadDataOwnReadFileMethodParallelThread()
{
    await await Task.Factory.StartNew(async () =>
        {
            List<Task> tasks = new List<Task>();

            for (int i = 0; i < filepaths.Count; i++)
            {
                int index = i;
                var t = ReadFile("/benchmarks/samplefiles/" + filepaths[i]);
                tasks.Add(t);
            }
            await TaskEx.WhenAll(tasks);

        });
}


public async Task b25LoadDataOwnReadFileMethodStorageFile()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");
    await await Task.Factory.StartNew(async () =>
    {
        for (int i = 0; i < filepaths.Count; i++)
        {
            filecontent = await ReadStorageFile(data, filepaths[i]);

        }
    });

}
public async Task b26LoadDataOwnReadFileMethodParallelStorageFile()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");
    List<Task> tasks = new List<Task>();

    for (int i = 0; i < filepaths.Count; i++)
    {
        int index = i;
        var t = ReadStorageFile(data, filepaths[i]);
        tasks.Add(t);
    }
    await TaskEx.WhenAll(tasks);

}
public async Task b27LoadDataOwnReadFileMethodParallelThreadStorageFile()
{
    StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    data = await data.GetFolderAsync("samplefiles");
    await await Task.Factory.StartNew(async () =>
    {
        List<Task> tasks = new List<Task>();

        for (int i = 0; i < filepaths.Count; i++)
        {
            int index = i;
            var t = ReadStorageFile(data, filepaths[i]);
            tasks.Add(t);
        }
        await TaskEx.WhenAll(tasks);

    });
}

public async Task b28LoadDataOwnReadFileMethodStorageFile()
{
    //StorageFolder data = await ApplicationData.Current.LocalFolder.GetFolderAsync("benchmarks");
    //data = await data.GetFolderAsync("samplefiles");
    await await Task.Factory.StartNew(async () =>
    {
        for (int i = 0; i < filepaths.Count; i++)
        {
            filecontent = await ReadStorageFile(ApplicationData.Current.LocalFolder, @"benchmarks\samplefiles\" + filepaths[i]);

        }
    });

}

public async Task<String> ReadStorageFile(StorageFolder folder, String filename)
{
    return await await Task.Factory.StartNew<Task<String>>(async () =>
    {
        String filec = "";
        StorageFile f = await folder.GetFileAsync(filename);
        using (var stream = await f.OpenStreamForReadAsync())
        {
            using (StreamReader r = new StreamReader(stream))
            {
                filec = await r.ReadToEndAsyncThread();
            }
        }
        return filec;
    });
}

public async Task<String> ReadFile(String filepath)
{
    return await await Task.Factory.StartNew<Task<String>>(async () =>
        {
            String filec = "";
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (var stream = new IsolatedStorageFileStream(filepath, FileMode.Open, store))
                {
                    using (StreamReader r = new StreamReader(stream))
                    {
                        filec = await r.ReadToEndAsyncThread();
                    }
                }
            }
            return filec;
        });
}

Как выполняются эти тесты:

public async Task RunBenchmark(String message, Func<Task> benchmarkmethod)
    {
        SystemTray.ProgressIndicator.IsVisible = true;
        SystemTray.ProgressIndicator.Text = message;
        SystemTray.ProgressIndicator.Value = 0;
        long milliseconds = 0;

        Stopwatch w = new Stopwatch();
        List<long> results = new List<long>(benchmarkruns);
        for (int i = 0; i < benchmarkruns; i++)
        {
            w.Reset();
            w.Start();
            await benchmarkmethod();
            w.Stop();
            milliseconds += w.ElapsedMilliseconds;
            results.Add(w.ElapsedMilliseconds);
            SystemTray.ProgressIndicator.Value += (double)1 / (double)benchmarkruns;
        }

        Log.Write("Fastest: " + results.Min(), "Slowest: " + results.Max(), "Average: " + results.Average(), "Median: " + results[results.Count / 2], "Maxdifference: " + (results.Max() - results.Min()),
                  "All results: " + results);


        ShowNotificationText((message + ":").PadRight(24) + (milliseconds / ((double)benchmarkruns)).ToString());
        SystemTray.ProgressIndicator.IsVisible = false;
    }
Результаты тестов

Вот ссылка на необработанные данные тестов:http://www.dehodev.com/windowsphonebenchmarks.xlsx

Теперь графики (каждый график показывает данные для загрузки 50 с помощью каждого метода, результаты все в миллисекундах)

Следующие тесты с 1 МБ не очень характерны для приложений. Я включил их здесь, чтобы дать лучший обзор того, как масштабируются эти методы.

Итак, подведем итоги: стандартный метод, используемый для чтения файлов (1.), всегда худший (за исключением случая, когда вы хотите прочитать 50 файлов по 10 Мб, но даже тогда существуют более эффективные методы).

Я также связываю это:await AsyncMethod () и await await Task.Factory.StartNew <TResult> (AsyncMethod)где утверждается, что обычно не полезно добавлять новое задание. Однако результаты, которые я вижу здесь, таковы, что вы просто не можете это предположить и всегда должны проверять, повышает ли добавление задачи производительность.

И последнее: я хотел опубликовать это на официальном форуме разработчиков Windows Phone, но каждый раз, когда я пытаюсь, я получаю сообщение «Неожиданная ошибка» ...

Обновление 2Выводы:

После просмотра данных вы можете ясно видеть, что независимо от размера файла каждый алгоритм масштабируется линейно по отношению к количеству файлов. Таким образом, чтобы упростить все, мы можем игнорировать количество файлов (мы будем просто использовать данные для 50 файлов в будущих сравнениях).

Теперь о размере файла: Размер файла важен. Мы видим, что когда мы увеличиваем размер файла, алгоритмы начинают сходиться. При размере файла 10 МБ предыдущий самый медленный алгоритм имеет место 4 из 8. Однако, поскольку этот вопрос в основном относится к телефонам, невероятно редко, когда приложения будут читать несколько файлов с таким большим количеством данных, даже файлы 1 МБ будут редкими для большинства приложений. Я предполагаю, что даже чтение 50 файлов размером 20 КБ является редкостью. Большинство приложений, вероятно, считывают данные в диапазоне от 10 до 30 файлов, каждый размером от 0,5 до 3 КБ. (Это только предположение, но я думаю, что это может быть точным)

Ответы на вопрос(1)

Ваш ответ на вопрос