Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Parallel.For. Проблемы с памьятью.


Автор: Bladerender 14.3.2008, 12:50
Помогите пожалуйста. Опытным путем было вычислено, что память девается именно при использовании паралелизма.
Код имеет такой вид.  GetSubTextInformation() - тут находится парсер, который парсит текстовую информацию и возвращает уже готовый результат. Получается, что память уходит в никуда и такими обьемами что просто ужасть.
Parallel.For(0, textParts.Count, delegate(int i)
                 {
                  article[i] = parse.GetSubTextInformation(textParts[i], _textId, i + 1);
                 });

При замене на просто for все становится как надо, никто никуда не ищезает, все очищается, и прога при роботе не превышает в памяти размера в 25 метров. Если с паралельностью то доходит до гига и потом каюк. 

Слышал что для каждого потока создается как бы своя куча, (я думаю там мусор и накапливается). Но немогу понять как это сделать. пробовал:

Parallel.For(0, textParts.Count, delegate(int i)
                 {
                  using(Article article = parse.GetSubTextInformation(textParts[i], _textId, i + 1))
                  article[i] = article;
                 });

все рано галяк. Пробовал так же внутри цыкла вызывать GC.Collect() но все равно безрезультатно.

Помогите.


Автор: marcusmae 14.3.2008, 19:14
Bladerender, похоже, что память съедают не фигурные скобочки, так что без кода парсера тут нечего сказать.

Автор: Bladerender 19.3.2008, 11:53
Код парсера возвращает коллекцию строк.
Тоесть класс, обьект которого возвращается имеет вид типа:

class Name
{
public string Name;
public List<string> collection = new List<string>();
}

Автор: marcusmae 19.3.2008, 12:16
Bladerender, вероятно, какая-то проблема с разделяемостью ресурсов или thread-safety. Кстати, вместо String-массива пользуйтесь StringBuilder, когда создаёте строку. Это - общие соображения. А конкретно я бы попробовал-таки разделить ресурсы, то есть либо сделать парсер статическим, либо создать его экземпляров по числу вычислительных потоков и поставить в Parallel.Do. С другой стороны покрутите и свой вариант - всегда же можно вместо некоторых кусков кода наставить временных заглушек и тем самым локализовать проблему.

Автор: Bladerender 25.3.2008, 14:15
Делал статическим,  один перец. Нащет Parallel.Do, то пока не пробовал, но думаю что это все равно ничего не даст, так как потоки сами создают в Parallel.For по екземпляру на поток. Я в этьм почти уверен.

Автор: rubbiroid 26.3.2008, 01:22
Не знаю, может поможет. Если у тебя внутри потока есть цикл, в котором создаются объекты - то сборщик мусора "старые" объекты удалит только после выхода из цикла. У меня такое было на загрузке фоток - вплоть до вываливания в нехватку памяти (когда более 2 гигабайт съедало). Мне помогло собственноручное удаление объктов внутри цикла.

Автор: marcusmae 27.3.2008, 01:00
Bladerender, 

окей, я для примеру написал генератор строк

Код

using System;
using System.Text;

namespace StParGen
{
    public static class StringGenerator
    {
        /// <summary>
        /// The maximum 21 bit value. 
        /// </summary>
        const int bit21max = 0x10ffff;

        /// <summary>
        /// Generate random string of the specified length.
        /// </summary>
        /// <param name="length">The string length.</param>
        /// <returns>The resulting string.</returns>
        public static string GetString(int length)
        {
            StringBuilder stringBuilder = new StringBuilder(length);
            Random random = new Random();
            for (int index = 0; index < length; index++)
            {
                int randomNumber = random.Next(bit21max);
                while ((randomNumber >= 0x00d800) && (randomNumber <= 0x00dfff))
                    randomNumber = random.Next(bit21max);
                String subString = Char.ConvertFromUtf32(randomNumber);
                for (int subIndex = index; (subIndex < length) &&
                    (subIndex - index < subString.Length); subIndex++)
                    stringBuilder.Append(subString[subIndex - index]);
            }
            return stringBuilder.ToString();
        }
    }
}


и параллельно-последовательный тест с ним :

Код

using System;
using System.Threading;

namespace StParGen
{
    class Program
    {
        const int length = 1000, count = 10000;

        static void Main(string[] args)
        {
            SequentialRun();
            // ParallelRun();

            Console.WriteLine("Done.");
            Console.ReadKey();
        }

        static void SequentialRun()
        {
            string[] str = new string[count];
            for (int index = 0; index < count; index++)
                str[index] = StringGenerator.GetString(length);
        }

        static void ParallelRun()
        {
            string[] str = new string[count];
            Parallel.For(0, count, delegate(int index)
            {
                str[index] = StringGenerator.GetString(length);
            });
        }
    }
}


И ничего, апокалипсиса не наступило : в обоих случаях пик памяти - примерно 55 мб.

Я может, поскромничал, нужны более агрессивные условия? smile Давайте, в общем, сделаем пример таким, чтобы описанное поведение воспроизводилось.

Автор: Bladerender 27.3.2008, 17:53
Странно как-то получается. У меня Ваш код тоже работает нормально. Без апокалипсиса. Я разберусь что не так и вкину свой генератор.

Автор: marcusmae 27.3.2008, 22:09
Цитата(Bladerender @  27.3.2008,  17:53 Найти цитируемый пост)
вкину свой генератор


Зачем же сразу выкидывать?! = Дайте его потестить, что ли...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)