Ответ 1
Вы не можете легко отличить отходы из-за переключения потоков и из-за конкуренции в кэше памяти. Вы МОЖЕТЕ измерять конфликт потоков. А именно, на linux вы можете cat/proc/PID/XXX и получать тонны статистики по каждой нити. ОДНАКО, поскольку упреждающий планировщик не собирается снимать себя в ногу, вы не получите больше, чем 30 ctx переключателей в секунду, независимо от того, сколько потоков вы используете. И это время будет относительно маленький против объем работы, которую вы выполняете. Реальная стоимость контекстного переключения - это загрязнение кэша. например существует высокая вероятность того, что у вас в большинстве случаев будут отсутствовать кеширование после того, как вы снова подключитесь к контексту. Таким образом, время работы ОС и контекст-счетчики имеют минимальное значение.
Что ДЕЙСТВИТЕЛЬНО ценно, так это соотношение между потоками кеш-строки в потоке. В зависимости от процессора, грязная кэш-строка, за которой следует чтение с одноранговым процессором, является SLOWER, чем прошивка кэш-памяти, потому что вы вынуждаете процессор peer записывать это значение в main-mem, прежде чем вы сможете даже начать читать. Некоторые Процессоры позволяют вытягивать из одноранговых кеш-строк, не ударяя main-mem.
Таким образом, ключ - это абсолютно минимизируйте ЛЮБЫЕ общие измененные структуры памяти. Сделайте все как можно более доступным для чтения.. Это ВКЛЮЧАЕТ общие буферы FIFO (включая пулы Executor). А именно, если вы использовали синхронизированную очередь - тогда каждая синхронизация -op - общая область грязной памяти. И более того, если скорость будет достаточно высокой, скорее всего, это приведет к тому, что ловушка ОС будет остановлена, ожидая мьютекса одноранговых потоков.
Идеал заключается в сегментировании ОЗУ, распределении на фиксированное число рабочих одной большой единицы работы, затем использовании счетчика-защелки или какого-либо другого барьера памяти (чтобы каждый поток касался только один раз). В идеале любые временные буферы предварительно выделяются вместо того, чтобы входить в пул разделяемой памяти и выходить из него (что приводит к конфликту с кешем). Java "синхронизировал" блокирует использование (за кулисами) общего пространства памяти хэш-таблицы и, таким образом, вызывает нежелательные грязные чтения, я не определил, избегают ли этого объекта блокировки java 5 Lock, но вы все еще используете стойки OS, которые выиграли Не помогайте в вашей пропускной способности. Очевидно, что большинство операций OutputStream запускают такие синхронные вызовы (и, конечно, обычно заполняют общий буфер потока).
Как правило, мой опыт заключается в том, что однопоточность выполняется быстрее, чем mulithreading для общего массива byte-array/object-array и т.д. По крайней мере, с упрощенными алгоритмами сортировки/фильтрации, с которыми я экспериментировал. Это верно как в Java, так и в C в моем опыте. Я не пробовал FPU intesive ops (например, dives, sqrt), где кеш-строки могут быть менее значимыми.
В принципе, если у вас один процессор, у вас нет проблем с кеш-линией (если только ОС не очищает кеш даже в общих потоках), но многопоточность покупает вас меньше, чем ничего. В гиперпотоке это та же самая сделка. В однопроцессорных конфигурациях кеша L2/L3 (например, AMD) вы можете найти какую-то выгоду. В многопроцессорных процессорах Intel BUS забудьте об этом - общая память для записи хуже, чем однопоточная.