Re[10]: Запись в массив double-ов из нескольких потоков
От: Nicht Россия  
Дата: 11.05.11 11:57
Оценка:
Здравствуйте, Donz, Вы писали:

D>ИМХО, сам массив не может кешироваться нитью. Кешироваться могут только поля (примитивные типы или ссылки на объекты).


Есть мнение что это не так. Вот тут человек матрицы перемножал. Так вот оказкалось быстрее транспонировать вторую матрицу и перемножать не строка на столбец а строку на строку как раз из за того что куски одномерного массива префетчатся в кэш линию. Причем выигрыш по времени был 230%.
Re[14]: Запись в массив double-ов из нескольких потоков
От: Nicht Россия  
Дата: 11.05.11 12:01
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


N>>>>Это все устарело с выходом JSR 133 (Java Memory Model).


PD>>>Речь идет о доступе к разным байтам (словам и т.д.) памяти. Потоки не имеют общих данных.


N>>Где идет речь?


PD>В задаче ТС.


В данной задаче проблема не в записи. Там нет рейса, так как потоки пишут в разные места и не пересекаются. Проблема могла быть как раз с видимостью резальтатов их работы в потоке, который читает данные из общего моссива. Если не сделать синхроназед ордер между писателями и читателем, читатель может просто не увидеть что сделал писатель и в итоге получить массив с почти проихвольным наполнением. Но вроде из исходника видно что там все нормально.
Re[15]: Запись в массив double-ов из нескольких потоков
От: Pavel Dvorkin Россия  
Дата: 11.05.11 12:04
Оценка:
Здравствуйте, Nicht, Вы писали:

N>Здравствуйте, Pavel Dvorkin, Вы писали:


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


N>>>>>Это все устарело с выходом JSR 133 (Java Memory Model).


PD>>>>Речь идет о доступе к разным байтам (словам и т.д.) памяти. Потоки не имеют общих данных.


N>>>Где идет речь?


PD>>В задаче ТС.


N>В данной задаче проблема не в записи. Там нет рейса, так как потоки пишут в разные места и не пересекаются. Проблема могла быть как раз с видимостью резальтатов их работы в потоке, который читает данные из общего моссива. Если не сделать синхроназед ордер между писателями и читателем, читатель может просто не увидеть что сделал писатель и в итоге получить массив с почти проихвольным наполнением. Но вроде из исходника видно что там все нормально.


Из сообщения ТС

ТС>Почему-то в итоге некоторые элементы массива


В итоге — надо понимать как "после того, как все потоки отработали", так (иначе какой же это итог ?). Так что поток, который читает данные из общего массива, работает тогда, когда вся эта деятельность уже закончена.
With best regards
Pavel Dvorkin
Re[11]: Запись в массив double-ов из нескольких потоков
От: Donz Россия http://donz-ru.livejournal.com
Дата: 11.05.11 12:09
Оценка:
Здравствуйте, Nicht, Вы писали:

D>>ИМХО, сам массив не может кешироваться нитью. Кешироваться могут только поля (примитивные типы или ссылки на объекты).

N>Есть мнение что это не так. Вот тут человек матрицы перемножал. Так вот оказкалось быстрее транспонировать вторую матрицу и перемножать не строка на столбец а строку на строку как раз из за того что куски одномерного массива префетчатся в кэш линию. Причем выигрыш по времени был 230%.

Не настолько плотно знаком с моделью памяти x86 и явовской, но навряд ли понятие кеширования нитью в яве равнозначно понятию кеширования данных на уровне процессора. Если какой-то кусок памяти отображен на кеш, то является ли это отображение валидным только для одного ядра или процесса, или сразу для всех и полностью для них прозрачно?
Если кеширование в яве равнозначно кешированию процессором, то получается, что мы не можем равноценно управлять процессом синхронизации данных из явы, так как для элементов массива отсутствует возможность сделать их volatile.
Re[16]: Запись в массив double-ов из нескольких потоков
От: Nicht Россия  
Дата: 11.05.11 12:10
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>В итоге — надо понимать как "после того, как все потоки отработали", так (иначе какой же это итог ?). Так что поток, который читает данные из общего массива, работает тогда, когда вся эта деятельность уже закончена.


Ну я мысли не умею читать так что решил уточнить. Так же уже обсуждалось что сентенция "после того, как все потоки отработали" тоже ничего не говорит о наличии синхронайзед ордера между записью и чтением.
Re: Запись в массив double-ов из нескольких потоков
От: Blazkowicz Россия  
Дата: 11.05.11 12:16
Оценка: 5 (1)
Нагуглилась ссылка по теме. Про volatile вообще и массивы в частности.

http://jeremymanson.blogspot.com/2009/06/volatile-arrays-in-java.html
Re[12]: Запись в массив double-ов из нескольких потоков
От: Nicht Россия  
Дата: 11.05.11 12:18
Оценка:
Здравствуйте, Donz, Вы писали:

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


D>>>ИМХО, сам массив не может кешироваться нитью. Кешироваться могут только поля (примитивные типы или ссылки на объекты).

N>>Есть мнение что это не так. Вот тут человек матрицы перемножал. Так вот оказкалось быстрее транспонировать вторую матрицу и перемножать не строка на столбец а строку на строку как раз из за того что куски одномерного массива префетчатся в кэш линию. Причем выигрыш по времени был 230%.

D>Не настолько плотно знаком с моделью памяти x86 и явовской, но навряд ли понятие кеширования нитью в яве равнозначно понятию кеширования данных на уровне процессора. Если какой-то кусок памяти отображен на кеш, то является ли это отображение валидным только для одного ядра или процесса, или сразу для всех и полностью для них прозрачно?


Вообще говоря, он не валиден ни для кого. Для этого есть system bus и протоколы валидации кеша. Современное железо обычно при валидации кеша оперируют не конкретным регистром а так называемой cache line. Это, грубо говоря, массив. По этому понятно, что выгодно валидейтить кэш когда у тебя не один регистр в линии проапдейтился а как можно больше.

D>Если кеширование в яве равнозначно кешированию процессором, то получается, что мы не можем равноценно управлять процессом синхронизации данных из явы, так как для элементов массива отсутствует возможность сделать их volatile.


В JMM вообще ничего не сказано про кеширование. Все это отдается на откуп оптимизирующему компилятору, а он будет это далеть согласно железной платформы. То что указало в статье в принципе карактерно для х86. Конечно если взять регистровые процессоры, то там все будет не так.
Re: Запись в массив double-ов из нескольких потоков
От: kuaw26 Россия  
Дата: 11.05.11 12:19
Оценка:
Прочитал всю ветку. Что-то мнения разошлись.

Еще раз опишу свою задачу:
Есть пул потоков кратный числу ядер в процессоре.
Основной поток запускает вычислительные потоки и ждет когда они отработают.
В каждом потоке тупо в цикле вызывается расчет математической функции и результат записывается в массив.
массив double-ов объявлен как final и создан в конструкторе.
Использую Fork/Join.

Nicht>Ну если гарантирован syncronized order между записью и чтение, то конечно все пучком.

Nicht>Этого можно добится несколькими способами, вызвать Thread.join() на пример. В спеке все это сказано.
Nicht>Однако если ты юзаешь ThreadPool то поток как бы и не завершится и будет alive, и там нужно делать синхроназед ордер вручную.

У меня как раз ThreadPool. Как мне синхронизовать в ручную?
И еще дайте сслку на спеку хочу сам почитать.
Re[2]: Запись в массив double-ов из нескольких потоков
От: kuaw26 Россия  
Дата: 11.05.11 12:23
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Нагуглилась ссылка по теме. Про volatile вообще и массивы в частности.

B>http://jeremymanson.blogspot.com/2009/06/volatile-arrays-in-java.html

Хороший блог, как раз одного из авторов jsr-133
Почитаю и в закладки однозначно
Re[2]: Запись в массив double-ов из нескольких потоков
От: Blazkowicz Россия  
Дата: 11.05.11 12:27
Оценка:
Здравствуйте, kuaw26, Вы писали:

K>Есть пул потоков кратный числу ядер в процессоре.

K>Основной поток запускает вычислительные потоки и ждет когда они отработают.
K>В каждом потоке тупо в цикле вызывается расчет математической функции и результат записывается в массив.
K>массив double-ов объявлен как final и создан в конструкторе.
K>Использую Fork/Join.
Встречных вопроса два.
— Есть ли тестовый код демонстрирующий проблему?
— Какие ещё есть гарантии что проблема вызвана именно записью в массив а не другой логикой?

K>И еще дайте сслку на спеку хочу сам почитать.

http://java.sun.com/docs/books/jls/
Странно что ссылка не на оракл ещё работает.
Re[2]: Запись в массив double-ов из нескольких потоков
От: Nicht Россия  
Дата: 11.05.11 12:36
Оценка:
Здравствуйте, kuaw26, Вы писали:

K>Прочитал всю ветку. Что-то мнения разошлись.


K>Еще раз опишу свою задачу:

K>Есть пул потоков кратный числу ядер в процессоре.
K>Основной поток запускает вычислительные потоки и ждет когда они отработают.
K>В каждом потоке тупо в цикле вызывается расчет математической функции и результат записывается в массив.
K>массив double-ов объявлен как final и создан в конструкторе.
K>Использую Fork/Join.

Тут надо читать доку по Fork/Join. У меня под рукой нет. По идее на методе ForkJoinPool.invokeAll() должно быть написано про синхронизацию памяти.

Nicht>>Ну если гарантирован syncronized order между записью и чтение, то конечно все пучком.

Nicht>>Этого можно добится несколькими способами, вызвать Thread.join() на пример. В спеке все это сказано.
Nicht>>Однако если ты юзаешь ThreadPool то поток как бы и не завершится и будет alive, и там нужно делать синхроназед ордер вручную.

K>У меня как раз ThreadPool. Как мне синхронизовать в ручную?

K>И еще дайте сслку на спеку хочу сам почитать.

Threads and Locks
Re[3]: Запись в массив double-ов из нескольких потоков
От: kuaw26 Россия  
Дата: 11.05.11 12:45
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Встречных вопроса два.

B>- Есть ли тестовый код демонстрирующий проблему?
Я выше приводил код, но он успешно работает, и проблему не демонстрирует.
Моя реальная прога устроена так же как и пример, не намного сложнее.
Если воспроизведется, то выложу весь код.

B>- Какие ещё есть гарантии что проблема вызвана именно записью в массив а не другой логикой?

Да нету никаких гарантий. У меня почему то перестало воспроизводится....
Хотя до этого 3 дня мозг парил.

B>http://java.sun.com/docs/books/jls/

Скачал. Почитаю. Можно читать только 3-ю редакцию? Или надо и 2-юу с 1-ой читать?
Re[3]: Запись в массив double-ов из нескольких потоков
От: kuaw26 Россия  
Дата: 11.05.11 12:59
Оценка:
N>Тут надо читать доку по Fork/Join. У меня под рукой нет. По идее на методе ForkJoinPool.invokeAll() должно быть написано про синхронизацию памяти.
ForkJoinPool.invokeAll()

Executes the given tasks, returning a list of Futures holding their status and results when all complete.
Future.isDone() is true for each element of the returned list.
Note that a completed task could have terminated either normally or by throwing an exception.
The results of this method are undefined if the given collection is modified while this operation is in progress.

Про память особо ничего не сказано, но сказано что метод вернет управление, после завершения всех задач.
Сбросят ли потоки в пуле свои кэши в этот момент или нет?
Re[17]: Запись в массив double-ов из нескольких потоков
От: kuaw26 Россия  
Дата: 11.05.11 13:03
Оценка:
Здравствуйте, Nicht, Вы писали:

N>Ну я мысли не умею читать так что решил уточнить. Так же уже обсуждалось что сентенция "после того, как все потоки отработали" тоже ничего не говорит о наличии синхронайзед ордера между записью и чтением.


А как обеспечить этот синхронайзед ордер? как я уже писал в одном из постов у меня пул потоков.
Может действительно дело в пуле потоков? типа JVM считает их живыми и не скидывает кэши или еще что?
Re[4]: Запись в массив double-ов из нескольких потоков
От: Nicht Россия  
Дата: 11.05.11 13:39
Оценка:
Здравствуйте, kuaw26, Вы писали:

N>>Тут надо читать доку по Fork/Join. У меня под рукой нет. По идее на методе ForkJoinPool.invokeAll() должно быть написано про синхронизацию памяти.

K>ForkJoinPool.invokeAll()

K>Executes the given tasks, returning a list of Futures holding their status and results when all complete.

K>Future.isDone() is true for each element of the returned list.
K>Note that a completed task could have terminated either normally or by throwing an exception.
K>The results of this method are undefined if the given collection is modified while this operation is in progress.

K>Про память особо ничего не сказано, но сказано что метод вернет управление, после завершения всех задач.

K>Сбросят ли потоки в пуле свои кэши в этот момент или нет?

Ну судя по тому что он возвращает Future, то твой код не правильный потому что не вызывает у этих future get() и тем самым вообще не дожидается завершения выполнения.
После беглого просмотра документации похоже что ты не совсем правильно используешь форкджойн. Вроде проще от RecursiveAction наследоваться. Там invokeAll гарантированно дожидается результатов из подтасков.
Re[5]: Запись в массив double-ов из нескольких потоков
От: kuaw26 Россия  
Дата: 11.05.11 14:48
Оценка:
Здравствуйте, Nicht, Вы писали:

N>Ну судя по тому что он возвращает Future, то твой код не правильный потому что не вызывает у этих future get() и тем самым вообще не дожидается завершения выполнения.

N>После беглого просмотра документации похоже что ты не совсем правильно используешь форкджойн. Вроде проще от RecursiveAction наследоваться. Там invokeAll гарантированно дожидается результатов из подтасков.

Я в самом начале делал и через RecursiveAction. И делал просто через fixedThreadPool + CyclicBarrier. Всяко разно пробовал.
И уже сам не въезжаю почему сейчас у меня работает, а до этого какой-то бред был.
Насчет неправильности. в джава доке же сказано, что "when all complete" и у всех фьючеров будет "isDone() is true" на кой тогда еще get() делать?
Что бы гарантировать тот самый ордеринг?

Причем что интересно. Дебажил под клипсой.
Захожу в метод расчета. Происходит вычисление функции (все нормально, значение > 0).
Потом происходит присваивание в массив и клипс показывает, что как бы присваивания не произошло.... i-ый элемент массива так и остался со значением 0
или это не прозошол сброс данных в память?


сначала я смог побороть это поведение кодом вида:
syncronized(массив)
{
массив[i] = значение.
}
но это же бред так писать. я же типа ускорял расчеты.
потом я такой код убрал. и после 101 переписывания пока все работает,... а я ломаю голову
Re[2]: Запись в массив double-ов из нескольких потоков
От: KRA Украина  
Дата: 11.05.11 20:59
Оценка:
Здравствуйте, kuaw26, Вы писали:

K>У меня как раз ThreadPool. Как мне синхронизовать в ручную?


http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CyclicBarrier.html
Re[2]: Запись в массив double-ов из нескольких потоков
От: Donz Россия http://donz-ru.livejournal.com
Дата: 12.05.11 07:39
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Нагуглилась ссылка по теме. Про volatile вообще и массивы в частности.

B>http://jeremymanson.blogspot.com/2009/06/volatile-arrays-in-java.html

Полезно, но по сути ничего нового. Как у автора получилось после окончания записи при join вызове получить невалидные значения в основной нити, не объясняет.
Re[6]: Запись в массив double-ов из нескольких потоков
От: abch-98-ru Россия  
Дата: 12.05.11 14:50
Оценка: 1 (1)
K>Насчет неправильности. в джава доке же сказано, что "when all complete" и у всех фьючеров будет "isDone() is true" на кой тогда еще get() делать?
не надо, в случае успешного исполнения, но exception пропустить можно.

K>Потом происходит присваивание в массив и клипс показывает, что как бы присваивания не произошло.... i-ый элемент массива так и остался со значением 0

K>или это не прозошол сброс данных в память?
могло произойти exception.

возможно, была у тебя бага в расчётах, сопровождаемая exception-ом.
она в твоём использовании fork&join "глотается".
в процессе борьбы с непонятками, меняя код, ты заодно и пофиксил либо код расчёта, либо входные данные.
чтоб в следующий раз не мучиться — дёргай get() и обрабатывай exception.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.