Вы не можете легко дифференцировать потери из-за переключения потоков и из-за нехватки памяти.Вы МОЖЕТЕ измерить конфликт между потоками. А именно, в linux вы можете выполнить cat / proc / PID / XXX и получить тонны подробной статистики по потокам.ОДНАКО, так как упреждающий планировщик не собирается стрелять сам в ногу, вы не получите больше, чем, скажем, 30 ctx-переключателей в секунду, независимо от того, сколько потоков вы используете. И это время будет относительномаленький по сравнению с объемом работы, которую вы делаете. Реальная стоимость переключения контекста - загрязнение кеша.Например, существует высокая вероятность того, что вы будете в большинстве случаев пропадать в кеше после переключения контекста. Таким образом, время ОС и количество переключений контекста имеют минимальное значение.
ДЕЙСТВИТЕЛЬНО ценным является соотношениегрязи между потокамиВ зависимости от процессора, грязная строка кэша, за которой следует одноранговое чтение, является МЕНЬШЕ, чем промах кэша - потому что вы должны заставить одноранговый ЦПУ записать его значение в main-mem, прежде чем вы даже сможете начать чтение. НекоторыеПроцессоры позволяют вам извлекать из одноранговых строк кэша, не нажимая main-mem.
Таким образом, ключ к абсолютному минимизации ЛЮБЫХ общих модифицированных структур памяти. Делайте все максимально доступным только для чтения. Это ВКЛЮЧАЕТ общий буфер FIFO(включая пулы исполнителей). А именно, если вы использовали синхронизированную очередь - тогда каждая синхронизация является общей грязной областью памяти.И более того, если скорость достаточно высока, она, скорее всего, вызовет прерывание ОС, ожидая мьютекса однорангового потока.
Идеально - сегментировать оперативную память, распределять ее среди фиксированного числа рабочих.одну большую единицу работы, затем используйте защелку обратного отсчета или какой-либо другой барьер памяти (чтобы каждый поток касался его только один раз).В идеале любые временные буферы предварительно выделяются вместо того, чтобы входить и выходить из общего пула памяти (что затем приводит к конфликту в кэше).«Синхронизированные» блоки Java используют (за кулисами) разделяемое пространство памяти хэш-таблицы и, таким образом, вызывают нежелательные «грязные» чтения. Я не определил, избегают ли объекты блокировки Java 5 этого, но вы все еще используете операционные системы, которые выигралине поможет в вашей пропускной способности.Очевидно, что большинство операций OutputStream инициируют такие синхронизированные вызовы (и, конечно, обычно заполняют общий буфер потока).
Вообще мой опыт показывает, что однопоточность быстрее, чем многопоточность, для обычного байтового массива / массива объектов и т. Д. По крайней мере с простыми алгоритмами сортировки / фильтрации, с которыми я экспериментировал.Это верно как для Java, так и для C, по моему опыту.Я не пробовал использовать операции FPU (например, divides, sqrt), где строки кэша могут иметь меньшее значение.
В основном, если вы используете один процессор, у вас нет проблем со строками кэша (если операционная система не всегда очищает кэш даже в общих потоках), но многопоточность покупает вас меньше, чем ничего.В гиперпоточности это то же самое.В конфигурациях кэш-памяти L2 / L3 с одним процессором (например, AMD) вы можете найти некоторое преимущество.В многопроцессорных процессорах Intel BUS забудьте об этом - общая память записи хуже, чем однопоточная.