Re[7]: распараллеливание и ресурсоёмкость
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.04.19 06:32
Оценка: +2
Здравствуйте, vvv848165@ya.ru, Вы писали:

VYR>запускаю с периодичностью 60 ms загрузка проца с распараллеливанием 14% без 12.5 %

Судя по всему, у вас просто слишком мало нагрузки.
То, что вы описываете — это числмолотилка отрабатывает за 0мс, а 12.5% отъедает тот код, который у вас выполняется между вызовами.
Я вам настоятельно советую перестать мерить производительность по таск менеджеру, и начать использовать взрослые инструменты.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: распараллеливание и ресурсоёмкость
От: vvv848165@ya.ru  
Дата: 17.04.19 06:44
Оценка:
Написал свой аналог класса Parallel — всё тоже самое — может дело в лямда выражениях и переменных

 class MyParallel
    {
        private struct Work {
            public Action<int> body;
            public int start;
            public int stop;
        }
        public static void For(int fromInclusive, int toExclusive, Action<int> body) 
        {
            int noCpu = Environment.ProcessorCount;
            Thread[]threads=new Thread[noCpu];
            Work[] work = new Work[noCpu];

            int Step=(toExclusive-fromInclusive)/noCpu;

            for (int i = 0, Index=fromInclusive; i < noCpu; i++,Index+=Step)
            {
                threads[i] = new Thread(ParameterizedThreadStart);
                work[i] = new Work();
                work[i].start = Index;
                work[i].stop = Index + Step;
                work[i].body = body;
            }

            work[noCpu - 1].stop = toExclusive;

            for (int i = 0; i < noCpu; i++)
                threads[i].Start(work[i]);

            for (int i = 0; i < noCpu; i++)
                threads[i].Join();
        }
        private static void ParameterizedThreadStart(object obj)
        {

            for (int i = ((Work)obj).start; i < ((Work)obj).stop; i++)
                ((Work)obj).body(i);
        }
    }
Re[2]: распараллеливание и ресурсоёмкость
От: okon  
Дата: 17.04.19 06:57
Оценка:
Здравствуйте, vvv848165@ya.ru, Вы писали:



VYR>Написал свой аналог класса Parallel — всё тоже самое — может дело в лямда выражениях и переменных


У меня вот с таким вариантом использования твоего метода For дает загрузку 100% всех ядер, а что у тебя за Body, нет ли там каких-то синхронизирующих элементов случаем,
например какой-нибудь вывод в UI

            For(1, 1000000, (i) =>
            {
                double x = 0;
                for (int j = 0; j < 100000; j++)
                {
                    x = x + Math.Sin(j);
                }
            });
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 17.04.2019 6:59 okon . Предыдущая версия .
Re[3]: распараллеливание и ресурсоёмкость
От: vvv848165@ya.ru  
Дата: 17.04.19 07:00
Оценка: 3 (1)
Здравствуйте, okon, Вы писали:

O>У меня вот с таким вариантом использования твоего метода For дает загрузку 100% всех ядер, а что у тебя за Body, нет ли там каких-то синхронизирующих элементов случаем,


на X... мне загрузка всех ядер ...
ты хоть вопрос читал???
Re[4]: распараллеливание и ресурсоёмкость
От: okon  
Дата: 17.04.19 07:11
Оценка:
Здравствуйте, vvv848165@ya.ru, Вы писали:

VYR>Здравствуйте, okon, Вы писали:


O>>У меня вот с таким вариантом использования твоего метода For дает загрузку 100% всех ядер, а что у тебя за Body, нет ли там каких-то синхронизирующих элементов случаем,


VYR>на X... мне загрузка всех ядер ...

VYR>ты хоть вопрос читал???

а С# паралелил при помощи Parallel.For — какая-то жуть — накидывает 5% нагрузки в лучшем случае
а иногда так глючит что распараллеленый код выполняется за большее количество времени


Т.е. я так понял у тебя задача выполнить паралельно за меньшее количество времени, чем одним потоком ?
По "закону сохранения энергии" это возможно только если ядра будут нагружены в сумме > 100%, например 26% каждое ядро.
а если хочется быстрее завершить задачу то надо использовать все 100%.

Как я сейчас понимаю ты не хочешь в 4 раза быстрее выполнить задачу, а просто хочешь каждое ядро по 25% нагрузить ?
Если так , то любая расчетная нагрузка будет занимать 100%, пока не выполнится.
Если у тебя там есть не только расчеты но и работа с устройствами, то надо смотреть как лучше.
Если хочется чтобы ядро немного "отдыхало" делай там Thread.Sleep(100) например или await Task.Delay(100) если используешь async/await.

            For(1, 1000000, async (i) =>
            {
                double x = 0;
                for (int j = 0; j < 1000; j++)
                {
                    x = x + Math.Sin(j);
                    await Task.Delay(1);
                }

            });


Например вот так
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 17.04.2019 7:15 okon . Предыдущая версия . Еще …
Отредактировано 17.04.2019 7:11 okon . Предыдущая версия .
всё перепробывал
От: vvv848165@ya.ru  
Дата: 17.04.19 09:33
Оценка:
даже копирование данных до и после не спасло

private struct MyDataThread {
            public double[][] tmp;
            public FilterSections[] fs;
            public double[] src;
            public long no_point;
        }
        private static MyDataThread MyAction(int ic, ParallelLoopState p, MyDataThread obj)
        {
            obj.tmp[ic] = new double[obj.no_point];
            obj.fs[ic].Next(obj.tmp[ic], obj.src);
            return obj;
        }


.................
Parallel.For<MyDataThread>(0, no_channel, () => {
                MyDataThread dt = new MyDataThread();
                dt.tmp = tmp;
                dt.fs = fs;
                dt.src = src;
                dt.no_point = no_point;
                return dt; 
            }, MyAction, (MyDataThread obg) => {
                tmp = obg.tmp;
            });


В чём может быть ещё потеря производительности

если в С++ всё по честному (если распределил на 4 проца — то выполнится в 4 раза быстрее)
то в С# какой-то облом (если распределил на 4 проца то выполнится только в 3 раза быстрее (а то и в два))
Отредактировано 17.04.2019 9:40 vvv848165@ya.ru . Предыдущая версия . Еще …
Отредактировано 17.04.2019 9:36 vvv848165@ya.ru . Предыдущая версия .
Re: всё перепробывал
От: Sharowarsheg  
Дата: 17.04.19 09:41
Оценка:
Здравствуйте, vvv848165@ya.ru, Вы писали:

VYR>В чём может быть ещё потеря производительности


VYR>если в С++ всё по честному (если распределил на 4 проца — то выполнится в 4 раза быстрее)


VYR>то в С# какой-то облом (если распределил на 4 проца то выполнится только в 3 раза быстрее (а то и в два))


GC, скорее всего. For Each, а также new double[], вот это всё. Можешь расчехлить Concurrency Visualizer и посмотреть.
Re[4]: распараллеливание и ресурсоёмкость
От: bzig  
Дата: 17.04.19 12:28
Оценка:
VYR>на X... мне загрузка всех ядер ...
VYR>ты хоть вопрос читал???

Чувак, как ты написал, так тебя все и поняли. А написал ты фигово.
Re: всё перепробывал
От: okon  
Дата: 17.04.19 18:16
Оценка:
VYR>если в С++ всё по честному (если распределил на 4 проца — то выполнится в 4 раза быстрее)
VYR>то в С# какой-то облом (если распределил на 4 проца то выполнится только в 3 раза быстрее (а то и в два))

А еще не раскрыто что делает
obj.fs[ic].Next(obj.tmp[ic], obj.src);

Что в этом методе Next делается ?
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[2]: всё перепробывал
От: vvv848165@ya.ru  
Дата: 18.04.19 08:06
Оценка:
Здравствуйте, okon, Вы писали:

O>Что в этом методе Next делается ?

no_filtres — 15
x.LongLength = 8192
public void Next(double[] y, double[] x)
        {

            for (int i = 0; i < no_filtres; i++)
                filters[i].Next(y, x);
        }

public void Next(double[] y, double[] x)
        {
            for (long i = 0; i < x.LongLength; i++)
            {
                double v0 = pregain * x[i] - a2 * v1 - a3 * v2;
                y[i] = v0 + b2 * v1 + v2;

                v2 = v1; v1 = v0;
            }
        }
Отредактировано 18.04.2019 8:08 vvv848165@ya.ru . Предыдущая версия .
Re[7]: распараллеливание и ресурсоёмкость
От: Ночной Смотрящий Россия  
Дата: 18.04.19 13:58
Оценка:
Здравствуйте, vvv848165@ya.ru, Вы писали:

VYR>загрузка проца


... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[3]: всё перепробывал
От: romangr Россия  
Дата: 18.04.19 14:31
Оценка: 3 (1)
Здравствуйте, vvv848165@ya.ru, Вы писали:

VYR>no_filtres — 15

VYR>x.LongLength = 8192

VYR>
VYR>public void Next(double[] y, double[] x)
VYR>        {

VYR>            for (int i = 0; i < no_filtres; i++)
VYR>                filters[i].Next(y, x);
VYR>        }

VYR>public void Next(double[] y, double[] x)
VYR>        {
VYR>            for (long i = 0; i < x.LongLength; i++)
VYR>            {
VYR>                double v0 = pregain * x[i] - a2 * v1 - a3 * v2;
VYR>                y[i] = v0 + b2 * v1 + v2;

VYR>                v2 = v1; v1 = v0;
VYR>            }
VYR>        }
VYR>


Учитывая, что CLR не разрешает иметь индексы у double[] больше 2146435071,
имеет смысл
for (long i = 0; i < x.LongLength; i++)


заменить на
for (int i = 0; i < x.Length; i++)


т.к. JIT туповат, и в 1-м случае не устраняет проверки на выход за границу массива.
Т.е. например код
public double M(double[] arr)
{
    double sum = 0;
    for (long i = 0; i < arr.LongLength; i++)
        sum += arr[i];
    return sum;
}


превращается в режиме x64 в
    L0000: sub rsp, 0x28
    L0004: vzeroupper
    L0007: vxorpd xmm0, xmm0, xmm0
    L000c: xor eax, eax
    L000e: mov ecx, [rdx+0x8]
    L0011: movsxd rcx, ecx
    L0014: test rcx, rcx
    L0017: jle L002d
    L0019: cmp rax, rcx
    L001c: jae L0032
    L001e: vaddsd xmm0, xmm0, [rdx+rax*8+0x10]
    L0025: inc rax
    L0028: cmp rcx, rax
    L002b: jg L0019
    L002d: add rsp, 0x28
    L0031: ret
    L0032: call 0x7ffdb9ec2660
    L0037: int3


а код
public double M(double[] arr)
{
    double sum = 0;
    for (int i = 0; i < arr.Length; i++)
        sum += arr[i];
    return sum;
}

превратится в
    L0000: vzeroupper
    L0003: vxorpd xmm0, xmm0, xmm0
    L0008: xor eax, eax
    L000a: mov ecx, [rdx+0x8]
    L000d: test ecx, ecx
    L000f: jle L0021
    L0011: movsxd r8, eax
    L0014: vaddsd xmm0, xmm0, [rdx+r8*8+0x10]
    L001b: inc eax
    L001d: cmp ecx, eax
    L001f: jg L0011
    L0021: ret

что несколько лучше по производительности.
В 32-х битном режиме разница еще больше.

Еще код типа
double[] val = new double[no];
for (int j = 0; j < no; j++)
        val[j] = x[j];

лучше заменить на
for (int j = 0; j < val.Length; j++)
        val[j] = x[j];

опять же из-за JIT, который не убирает проверки на выход за границу массива на каждой итерации в 1-м случае.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[3]: всё перепробывал
От: alexzzzz  
Дата: 19.04.19 11:52
Оценка:
Здравствуйте, vvv848165@ya.ru, Вы писали:

Ты можешь выложить код в самодостаточном виде, чтобы компилировался и запускался? Чтобы просто взять да посмотреть, что происходит. Иначе вся эта тема — пальцем в небо и гадание на кофейной гуще. Не понимаю, как другим удаётся советовать что-то осмысленное, не видя работающего кода.
Отредактировано 19.04.2019 11:56 alexzzzz . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.