Мне нравится , объяснение Jenkov
, Синхронизируемые блоки в Java отмечены с synchronized
ключевое слово. Синхронизируемый блок в Java синхронизируется на некотором объекте. Все синхронизируемые блоки, синхронизируемые на том же объекте, могут только иметь одно выполнение потока в них одновременно. Все другие потоки, пытающиеся ввести синхронизируемый блок, заблокированы, пока поток в синхронизируемом блоке не выходит из блока.
разблокировать (синхронизировал блок, или выход метода) монитора happens-before
каждая последующая блокировка (синхронизировал блок или запись метода) того же самого монитора.
Синхронизируемые блоки гарантируют, что, когда поток выходит из синхронизируемого блока, все обновленные переменные будут сброшены в к оперативной памяти, и все переменные, к которым получают доступ в синхронизируемом блоке, будут считаны в из оперативной памяти.
От Java 5
синхронизируемый механизм был первым механизмом Java для синхронизации доступа к объектам, совместно использованным несколькими потоками. Синхронизируемый механизм не очень усовершенствован все же. Именно поэтому Java 5
заставил полный набор concurrency utility
классы помогать разработчикам реализовать более мелкомодульное управление совместным выполнением, чем, что Вы получаете с синхронизируемым.
Для большого объема данных инструкция bswap
(доступна в Visual C ++ в рамках _byteswap_ushort
, _byteswap_ulong
и _byteswap_uint64
intrinsics) - это правильный путь. Это даже превосходит рукописную сборку. Они недоступны в чистом C # без P / Invoke, поэтому:
PS: Многие люди не знают о встроенных функциях подкачки байтов. Их производительность поразительна, вдвойне лучше для данных с плавающей запятой, потому что они обрабатываются как целые числа. Невозможно победить его без ручного кодирования загрузки вашего регистра для каждого отдельного варианта использования подкачки байтов, и если вы попробуете это, вы, вероятно, получите больший удар в оптимизаторе, чем когда-либо.
Я думал рассмотреть два uint types как тип ulong
Ну, это также поменяет местами два значения uint, что может быть нежелательно ...
Вы можете попробовать какой-нибудь код C # в небезопасном режиме, который на самом деле может работать достаточно хорошо. Например:
public static unsafe void SwapInts(uint[] data) {
int cnt = data.Length;
fixed (uint* d = data) {
byte* p = (byte*)d;
while (cnt-- > 0) {
byte a = *p;
p++;
byte b = *p;
*p = *(p + 1);
p++;
*p = b;
p++;
*(p - 3) = *p;
*p = a;
p++;
}
}
}
На моем компьютере пропускная способность составляет около 2 ГБ в секунду.
Вы можете просто переосмыслить проблему, это не должно быть узким местом. Возьмем наивный алгоритм (написанный на сборке CLI, просто для удовольствия). Предположим, что число, которое нам нужно, находится в локальном номере 0
LDLOC 0
SHL 24
LDLOC 0
LDC.i4 0x0000ff00
SHL 8
OR
LDLOC 0
LDC.i4 0x00ff0000
SHL.UN 8
OR
LDLOC 0
SHL.UN 24
OR
Максимум 13 (x86) ассемблерных инструкций на число (и, скорее всего, интерпретатор будет еще умнее, если будет использовать умные регистры). И это не может быть более наивным, чем это.
Теперь сравните это со стоимостью
Если 13 инструкций на число составляют значительную часть времени выполнения, то вы выполняете ОЧЕНЬ высокопроизводительную задачу и должны иметь ввод в правильном формате ! Вы также, вероятно, не будете использовать управляемый язык, потому что вам нужен гораздо больший контроль над буферами данных и чем-то еще, и без дополнительной проверки границ массива.