- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
double[,] ThreadMatrixMult(int size, double[,] m1, double[,] m2)
{
double[,] result = new double[size, size];
var threads = new List<Thread>(size);
for (int i = 0; i < size; i++)
{
var t = new Thread( ti =>
{
int ii = (int)ti;
for (int j = 0; j < size; j++)
{
result[ii, j] = 0;
for (int k = 0; k < size; k++)
{
result[ii, j] += m1[ii, k] * m2[k, j];
}
}
});
threads.Add(t);
t.Start(i);
}
foreach (Thread thread in threads)
thread.Join();
return result;
}
LispGovno 21.01.2015 21:30 # +1
lorc 21.01.2015 21:52 # +2
Хотя можно переписать на Эрланге, чё. Там создание и уничтожение потоков - дешевая операция.
bormand 21.01.2015 22:02 # +1
lorc 22.01.2015 14:21 # +1
kipar 22.01.2015 14:53 # 0
Зато сложение и умножение - недешевая. Вроде тут на ГК писали что он в сотни раз дольше матрицы умножает, чем сишный код.
lorc 22.01.2015 14:56 # 0
Ну серьезно, без смайликов и зеленого юмор уже непонятен?
kipar 22.01.2015 16:39 # +1
3.14159265 21.01.2015 21:56 # +4
>t.Start(i);
>thread.Join();
Вот тебе бабушка и AssParallel.
Не верю что в шарп до сих пор не завезли нормальные тредпулы c work stealing.
LispGovno 21.01.2015 21:58 # 0
bormand 21.01.2015 22:00 # 0
Они же исполняются на том самом тредпуле. Не?
LispGovno 21.01.2015 22:01 # 0
http://govnokod.ru/17421#comment262107
bormand 21.01.2015 22:03 # 0
3.14159265 21.01.2015 22:05 # 0
LispGovno 21.01.2015 22:48 # 0
roman-kashitsyn 22.01.2015 10:00 # 0
bormand 22.01.2015 10:02 # 0
roman-kashitsyn 22.01.2015 11:00 # +1
std::make_exception
std::current_exception
О деталях я как-то не думал, но подозреваю, что там больше одного копирования (при выбрасывании) и не происходит, а исключения изначально живут в памяти, доступной всем потокам.
laMer007 22.01.2015 11:12 # 0
bormand 22.01.2015 11:12 # 0
Меня вот это смущает: holding a reference to the exception object, or a copy of the exception object, it is implementation-defined if a copy is made. Передача потенциальной ссылки в соседний поток как-то подозрительно смотрится...
bormand 22.01.2015 11:27 # 0
Похоже на то. Адреса не стековые, когда исключение ловишь. Походу throw их куда-то заныкивает, пока тип еще известен.
bormand 22.01.2015 11:40 # +1
P.S. Т.е. throw само по себе может кинуть bad_alloc вместо нужного исключения?
roman-kashitsyn 22.01.2015 12:40 # +1
Может, конечно, если исключение аллоцирует много памяти.
Думаю, std::exception::what() возвращает const char* вместо std::string не просто так :)
Не исключено, что сами исключения могут аллоцироваться в отдельном резервном участке памяти (иначе как кинуть bad_alloc?), но это только догадки.
bormand 22.01.2015 13:02 # 0
Заранее создать один экземпляр std::bad_alloс на чорный день. Его можно даже не пересоздавать, а всегда возвращать один и тот же. Он всё равно иммутабельный, и никто его не испортит.
bormand 22.01.2015 13:04 # 0
Вот это бесит, кстати. Из-за этого нельзя построить этот what() на лету.
laMer007 22.01.2015 13:52 # 0
bormand 22.01.2015 14:49 # 0
3.14159265 21.01.2015 22:02 # 0
Короче promise асинхронный стандартный. В js такого море.
LispGovno 21.01.2015 22:50 # 0
3.14159265 21.01.2015 23:08 # +1
Говорят что он хорош когда много мелких заданий.
http://literatejava.com/threading/fork-join-parallelization-feature-or-problem/
http://stackoverflow.com/questions/8206318/is-javas-fork-and-join-thread-pool-is-good-for-executing-io-bound-task
Проблема в оверхеде: work-stealing causes high contention
LispGovno 21.01.2015 23:23 # 0
LispGovno 21.01.2015 23:50 # 0
3.14159265 22.01.2015 00:16 # +1
Очередь тут не выступает бутылочным горлышком.
Но допустим у нас 64 ядра. А задачи мелкие и быстро исполняются (микросекунды, сопоставимо со временем захвата лочки), то нам надо очень быстро накладывать задачи (желательно тоже в несколько потоков), и быстро их забирать. В случае рекурсивных заданий потоки сами же и ложат задания в очередь.
И тогда грубо говоря 32 потока ждут чтобы положить, и 32 ждут чтобы взять. И все они борются за право поменять одну и ту же область памяти (счётчик или указатель). И наступает пиздец...
В многопоточном кодинге важно чтобы не было бутылочных горлышек в виде мест, где расспаралелить нельзя (закон Амдала). Очередь это и есть такое место. Просто на типичных задачах при количествах ядер 4,8 это еще не было заметно.
Логичным и простым решением кажется сделать 64 очереди у 64 потоков.
А теперь советую подумать, как организовать точку входа, так, чтобы она раскладывала задания между очередями и не создавала contention?
LispGovno 22.01.2015 00:51 # 0
раунд робин
bormand 22.01.2015 00:56 # +1
У лентяев много накопится, остальным делать нефиг будет.
LispGovno 22.01.2015 00:58 # 0
3.14159265 22.01.2015 01:08 # +2
Поэтому переходим к следующему логичному вопросу (который поцчему-то многие часто игнорируют)
Как сделать атомик счётчик чтоб 64 потока при его инкременте не соревновались за один и тот же участок памяти?
bormand 22.01.2015 01:16 # +1
Переместив контеншн в аллокатор, лол.
LispGovno 22.01.2015 01:37 # +2
bormand 22.01.2015 01:44 # +1
LispGovno 22.01.2015 01:58 # +1
defecate-plusplus 22.01.2015 02:05 # +2
LispGovno 22.01.2015 03:48 # +1
LispGovno 22.01.2015 00:53 # 0
да никак они не возвращаются. тупо один поток из тредпула извлекли он реально занят на ожидании события. лажа вообщем тупое просирание процессорного времени, системных ресурсов и мегабайта под стек, что в высоконагруженных серверах жопа
3.14159265 21.01.2015 23:19 # +2
Проблема обычных пулов в том что они строятся на очереди, а очередь по сути двухпоточная (одна лочка или CAS на put, другая на take), и выше она не масштабируется.
Вот надо придумать какую-то концепцию чтоб можно было добавлять задачи с N потоков и раскладывать их же по M исполнителям.
То есть если брать очереди, то желательно иметь их M штук чтоб contentionа не было и оно параллелилось. Но как их координировать?
Вот кто-то сел и подумал что есть рекурсивные задачи, которые внутри себя содержат другие задачи, итд, если их спаунить в локальной очереди, то contention сильно уменьшится. А координацию сделал через скан чужих очередей (пока чужой поток занят делом). Понятно что это порождает некий оверхед.
В случае IO задачи просто не успевают исполняться так быстро, что потоки не успевают накладывать новые, то есть очередь НЕ становится бутылочным горлышком. Потому work-stealing не очень-то и нужен.
Есть другой менее известный паттерн называется Disruptor. Там всё еще круче, правда IO он совсем не любит.
Изложение немного сбойное и косноязычное, поскольку я устал, но надеюсь мысль зачем это всё городится понятна.
Dummy00001 22.01.2015 04:01 # 0
честно говоря - нет. по моему вы просто страдаете фигней.
потоки и скедулинг были и будут оставатся относительно дорогими. потому что скедулинг был и все еще остается в сердце экспоненциальным алгоритмом - сколько бы на него O(1) помады не красили.
если у вас lock contention на очереди задач становится проблемой, то это однозначная индикация что у вас задачи слишком мелкие.
другими словами: если вы будете всякой мелкой херней спамить хардварные ресурсы (проц тоже железо!) то у вас никогда ничего скалироватся не будет.
yamamoto 21.01.2015 22:57 # +2
someone 22.01.2015 06:12 # +3
guest 28.02.2017 09:52 # 0
Цена: 9900 р.
Размер: 29 х 34 х 9 см
Материалы: Медь, Бархат, Дерево ® <a href=https://vipcu.ru/category/derevyannye-klyuchnitsy/>такой</a>
<a href=https://vipcu.ru/derevyannaya-klyuchnitsa-tt-s-nagradami-sssr-16-276/><img>https://vipcu.ru/wa-data/public/shop/products/48/25/2548/images/4429/4429.200x0.jpg</img></a> <a href=https://vipcu.ru/derevyannaya-klyuchnitsa-nastennaya-denezhnoe-derevo/><img>https://vipcu.ru/wa-data/public/shop/products/58/08/858/images/4813/4813.200x0.jpg</img></a> <a href=https://vipcu.ru/derevyannaya-klyuchnitsa-podkova-s-zolocheniem-14-150/><img>https://vipcu.ru/wa-data/public/shop/products/43/25/2543/images/4404/4404.200x0.jpg</img></a>
guest 28.02.2017 13:49 # +2