Подтвердить что ты не робот

Вы используете параллельные расширения?

Я надеюсь, что это не злоупотребление stackoverflow; В последнее время я видел здесь несколько больших вопросов о параллельных расширениях, и это вызвало мой интерес.

Мой вопрос: Вы используете параллельные расширения, и если да, то как?

Меня зовут Стивен Туб, и я нахожусь в команде Parallel Computing Platform в Microsoft. Мы являемся группой, ответственной за параллельные расширения. Мне всегда интересно узнать, как разработчики используют параллельные расширения (например, Parallel.For, PLINQ, ConcurrentDictionary и т.д.), Положительный опыт, который у вас был, отрицательный опыт, который у вас был, запросы функций на будущее, и поэтому на.
Если вы захотите поделиться такой информацией, пожалуйста, сделайте это, либо здесь, либо в качестве ответа на этот вопрос, либо мне конфиденциально по электронной почте в stoub at microsoft dot com.

Я очень надеюсь услышать от вас.

Спасибо заранее!

4b9b3361

Ответ 1

Я использую TPL для выполнения вложенных вызовов Parallel.ForEach. Поскольку я обращаюсь к словарям из этих вызовов, я должен использовать ConcurrentDictionary. Хотя это хорошо, у меня есть несколько проблем:

  • Делегаты внутри ForEach не выполняют много работы, поэтому я не получаю много parallelism. Кажется, что система проводит большую часть времени, соединяясь с потоками. Было бы неплохо, если бы был способ выяснить, почему он не улучшается concurrency и улучшает его.

  • Внутренние итерации ForEach превышают экземпляры ConcurrentDictionary, что приведет к тому, что система потратит большую часть своих счетчиков времени на словарь, если я не добавил кеш-перечислитель.

  • Многие из моих экземпляров ConcurrentDictionary на самом деле являются наборами, но нет ConcurrentSet, поэтому мне пришлось реализовать свои собственные с помощью ConcurrentDictionary.

  • ConcurrentDictionary не поддерживает синтаксис инициализации объекта, поэтому я не могу сказать var dict = new ConcurrentDictionary<char, int> { { 'A', 65 } };, что также означает, что я не могу назначить литералы ConcurrentDictionary для членов класса.

  • Есть несколько мест, где мне нужно найти ключ в ConcurrentDictionary и вызвать дорогостоящую функцию для создания значения, если оно не существует. Было бы неплохо, если бы была перегрузка GetOrAdd, которая принимает addValueFactory, так что значение может быть вычислено только в том случае, если ключ не существует. Это можно моделировать с помощью .AddOrUpdate(key, addValueFactory, (k, v) => v), но это добавляет накладные расходы на дополнительный вызов делегата для каждого поиска.

Ответ 2

Я еще не использовал его еще много, но я определенно не обращал внимания на его использование и искал возможности в нашей базе кода, чтобы использовать его (к сожалению, мы .NET-2.0 связаны со многими из наши проекты все еще на данный момент). Один маленький камень, который я придумал, был уникальным счетчиком слов. Я думаю, что это самая быстрая и кратчайшая реализация, которую я могу придумать - если кто-то сможет сделать это лучше, это будет удивительно:

private static readonly char[] delimiters = { ' ', '.', ',', ';', '\'', '-', ':', '!', '?', '(', ')', '<', '>', '=', '*', '/', '[', ']', '{', '}', '\\', '"', '\r', '\n' };
private static readonly Func<string, string> theWord = Word;
private static readonly Func<IGrouping<string, string>, KeyValuePair<string, int>> theNewWordCount = NewWordCount;
private static readonly Func<KeyValuePair<string, int>, int> theCount = Count;

private static void Main(string[] args)
{
    foreach (var wordCount in File.ReadAllText(args.Length > 0 ? args[0] : @"C:\DEV\CountUniqueWords\CountUniqueWords\Program.cs")
        .Split(delimiters, StringSplitOptions.RemoveEmptyEntries)
        .AsParallel()
        .GroupBy(theWord, StringComparer.OrdinalIgnoreCase)
        .Select(theNewWordCount)
        .OrderByDescending(theCount))
    {
        Console.WriteLine(
            "Word: \""
            + wordCount.Key
            + "\" Count: "
            + wordCount.Value);
    }

    Console.ReadLine();
}

private static string Word(string word)
{
    return word;
}

private static KeyValuePair<string, int> NewWordCount(IGrouping<string, string> wordCount)
{
    return new KeyValuePair<string, int>(
        wordCount.Key,
        wordCount.Count());
}

private static int Count(KeyValuePair<string, int> wordCount)
{
    return wordCount.Value;
}

Ответ 3

Я использовал его в своем проекте MetaSharp. У меня есть компиляционный конвейер MSBuild для DSL, и один из этапов - это этап Many to Many. Этап M: M использует .AsParallel.ForAll(...).

Здесь фрагмент:

protected sealed override IEnumerable<IContext> Process()
{
    if (this.Input.Count() > 1)
    {
        this.Input
            .AsParallel<IContext>()
            .ForAll(this.Process);
    }
    else if (this.Input.Any())
    {
        this.Process(this.Input.Single());
    }

    return this.Input.ToArray();
}

Ответ 4

Мы не используем его широко, но это, безусловно, пригодится.

Мне удалось сократить время выполнения нескольких наших более длительных модульных тестов примерно до 1/3 их первоначального времени, просто обернув некоторые из более длительных шагов при вызове Parallel.Invoke().

Мне также нравится использовать параллельные библиотеки для тестирования безопасности потоков. Я поймал и сообщил пару проблем с нитями с Ninject с кодом примерно так:

var repositoryTypes = from a in CoreAssemblies
                    from t in a.GetTypes()
                    where t.Name.EndsWith("Repository")
                    select t;
repositoryTypes.ToList().AsParallel().ForAll(
    repositoryType => _kernel.Get(repositoryType));

В нашем фактическом производственном коде мы используем некоторые параллельные расширения для выполнения некоторых действий по интеграции, которые должны запускаться каждые несколько минут и которые состоят в основном из вытаскивания данных из веб-служб. Это особенно важно для parallelism из-за высокой задержки, присущей веб-соединениям, и позволяет нашим задачам завершить работу до того, как они снова начнут работать.

Ответ 5

Я использую ConcurrentDictionary, который хранит 100 миллионов + элементов. В настоящее время мое приложение использует около 8 ГБ памяти. Затем ConcurrentDictionary решает, что хочет расти на другом Add. И он хочет вырастить LOT, по-видимому (некоторый внутренний алгоритм prima), поскольку у него заканчивается память. Это на x64 с 32 ГБ памяти.

Поэтому я хотел бы, чтобы логическое значение блокировало автоматическое восстановление/повторное использование (параллельного) словаря. Затем я инициализировал словарь при создании с фиксированным набором ведер (это не то же самое, что фиксированная емкость!). И со временем это станет немного медленнее, так как в ведре все больше и больше предметов. Но это предотвратит повторное использование и выпадение памяти слишком быстро и без необходимости.