Есть следующий (сильно упрощенный код ввиду публичного рассмотрения) c# код
using System;
using System.Collections;
using System.Runtime;
namespace Hashtablebenchmark
{
class Program
{
static void Main(string[] args)
{
int n = 10000000;
for (int j=0; j<10; ++j) {
var startTime = DateTime.Now;
Hashtable hashtable = new Hashtable(n);
for (int i = 1; i <= n; ++i)
hashtable.Add(i, 1.0f / i);
Console.WriteLine("m[100] = " + hashtable[100]);
var endTime = DateTime.Now;
var time = endTime- startTime;
Console.WriteLine("Took: " + time.TotalMilliseconds / 1e3 + "s");
}
Console.ReadKey();
}
}
}
И java код (запущен с VM options -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC -XX:+AggressiveOpts)
package hashtablebenchmark;
import java.util.HashMap;
public class Hashtablebenchmark {
public static void main(String[] args) {
int n = 10000000;
for (int j=0; j<10; ++j) {
long startTime = System.currentTimeMillis();
HashMap hashtable = new HashMap(n);
for(int i=1; i<=n; ++i)
hashtable.put(i, 1.0f / i);
System.out.println("m[100] = " + hashtable.get(100));
long time = System.currentTimeMillis() - startTime;
System.out.println("Took: " + time / 1e3 + "s");
}
}
}
Результаты на одной и той же машине (win7 professional sp1 x64) следующие:
C# (собран в vs13 в release mode и запущен отдельно как console app вне студии ):
m[100] = 0.01
Took: 2.0317968s
m[100] = 0.01
Took: 3.669633s
m[100] = 0.01
Took: 2.6347365s
m[100] = 0.01
Took: 3.5336466s
m[100] = 0.01
Took: 3.6256374s
m[100] = 0.01
Took: 3.489651s
m[100] = 0.01
Took: 3.0076992s
m[100] = 0.01
Took: 3.5466453s
m[100] = 0.01
Took: 1.8048195s
m[100] = 0.01
Took: 3.1646835s
Как видите преимущество в производительности JVM в данном коде примерно на порядок (в 10 раз).
Что я делаю не так? Может быть где-то ошибка в коде? Если нет, то как ускорить C# код хотя бы до уровня JVM?
Надеюсь на помощь господ, умудренных опытом в C#. Спасибо
Здравствуйте, mapnik, Вы писали:
M>Что я делаю не так? Может быть где-то ошибка в коде? Если нет, то как ускорить C# код хотя бы до уровня JVM? M>Надеюсь на помощь господ, умудренных опытом в C#. Спасибо
Здравствуйте, tofox2, Вы писали:
T>Заменить Hashtable на Dictionary<int, float>
Хотя ваш совет абсолютно правилен, этого нельзя сделать по некоторым причинам .
Я не совсем точно сформулировал свой вопрос. Я хотел бы понять у C# и шарепоинт-программистов, почему clr так легко проседает на таком простом кусочке кода по отнашению к JVM . Именно поэтому тема находится в СВ.
Хочу услышать их мнение .
Здравствуйте, mapnik, Вы писали:
M>Я не совсем точно сформулировал свой вопрос. Я хотел бы понять у сC# и шарепоинт-программистов, почему clr так легко проседает на таком простом кусочке кода по отнашению к JVM . Именно поэтому тема находится в СВ. M>Хочу услышать их мнение .
Здравствуйте, mapnik, Вы писали:
M>Я не совсем точно сформулировал свой вопрос. Я хотел бы понять у сC# и шарепоинт-программистов, почему clr так легко проседает на таком простом кусочке кода по отнашению к JVM . Именно поэтому тема находится в СВ. M>Хочу услышать их мнение .
Может быть потому что это — говнокод, и никто не будет оптимизировать рантайм под него?
var hashtable = new System.Collections.Generic.Dictionary<int, double>(n);
1) Не могу использовать Dictionary. Он не thread-safe, а Hashtable is thread safe.
2) Я пробовал прогонять код для более короткого цикла (напр. 100000) и clr и jvm имеют одну производительность. Такое ощущение что CLR GC не справляется. Это также подтверждается вызовом GCSettings.LatencyMode на LowLatency. Цифры сразу взлетают вверх.
Здравствуйте, mapnik, Вы писали:
M>Вы не добавили аргумент -server. Это конечно моя ошибка, я так часто его использую что просто забыл написать про это
Здравствуйте, mapnik, Вы писали:
M>1) Не могу использовать Dictionary. Он не thread-safe, а Hashtable is thread safe.
Кто тебе такой бред сказал? И то и другое — не thread safe. Оба поддерживают режим произвольного количества читателей. Наконец, есть действительно thread safe словарь — ConcurrentDictionary.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Кто тебе такой бред сказал? И то и другое — не thread safe. Оба поддерживают режим произвольного количества читателей. Наконец, есть действительно thread safe словарь — ConcurrentDictionary.
Вы документацию производителя вообще читаете? Впрочем зачем это шарепоинт-программистам, это же не модно — читать.
Hashtable is thread safe for use by multiple reader threads and a single writing thread. It is thread safe for multi-thread use when only one of the threads perform write (update) operations, which allows for lock-free reads provided that the writers are serialized to the Hashtable.
A Dictionary can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. In the rare case where an enumeration contends with write accesses, the collection must be locked during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.
И нет я не могу использовать ConcurrentDictionary — мне нужно поддерживать версии .net < 4.
M>A Dictionary can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. In the rare case where an enumeration contends with write accesses, the collection must be locked during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.
Ну совсем как HashMap:
If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.
Здравствуйте, Yoriсk, Вы писали:
Y>Ну совсем как HashMap: Y>Но HashMap можно, а Dictionary — нет. Интересно.
Нет не совсем. Hashtable разрешает один writer вместе с multiple readers без locking, а Dictionary нет. Это именно мой сценарий использования. В Dictionary при таком варианте использования нужно использовать ReaderWriterLock, который делает его очень медленным.
Впрочем в CLR похоже все не быстрое.
Тебе нужно перевести "If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally"?
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Тебе нужно перевести "If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally"?
Еще раз (видимо у меня с русским плохо, не могу объяснить нормально)
Both classes allows multiple readers at once without lock, both must be locked for multiple writers. The difference is, that Hashtable allows one writer together with multiple readers without locking, while this is not safe with Dictionaty. So with Hashtable only writes must be locked. If both Keys and Values are reference-type (and so no boxing/unboxing is needed), Hashtable can be faster than Dictionary in scenarios with many readers and one (or more) writers, because readers don't have to wait for lock at all. With Dictionary the same scenario requires using ReaderWriterLock.
Поэтому невозможно использовать Dictionary в моем случае (это уже проверено). Тема появилась не от балды.
Здравствуйте, mapnik, Вы писали:
M>Нет не совсем. Hashtable разрешает один writer вместе с multiple readers без locking, а Dictionary нет. Это именно мой сценарий использования. В Dictionary при таком варианте использования нужно использовать ReaderWriterLock, который делает его очень медленным.
1) ReaderWriterLockSlim
2) что мешает побенчить с 1)
Здравствуйте, mapnik, Вы писали:
Y>>Ну совсем как HashMap: Y>>Но HashMap можно, а Dictionary — нет. Интересно.
M>Нет не совсем. Hashtable разрешает один writer вместе с multiple readers без locking, а Dictionary нет. Это именно мой сценарий использования. В Dictionary при таком варианте использования нужно использовать ReaderWriterLock, который делает его очень медленным. M>Впрочем в CLR похоже все не быстрое.
Еще раз, по порядку: cравниваются реализации на Java и С#. Вы говорите, что реализация на HashMap, который thread-safe только в случае immutable на java вас устраивает, а на Dictionary на .net — нет. Поэому в Dictionary нужен ReaderWriterLock, а в HashMap, ... какая-то аналогичная конструкция на java(ReadWritLock?).
Здравствуйте, Yoriсk, Вы писали:
Y>Еще раз, по порядку: cравниваются реализации на Java и С#. Вы говорите, что реализация на HashMap, который thread-safe только в случае immutable на java вас устраивает, а на Dictionary на .net — нет. Поэому в Dictionary нужен ReaderWriterLock, а в HashMap, ... какая-то аналогичная конструкция на java(ReadWritLock?). Y>Вот я и спрашиваю: а в чём, собственно, разница?
Ок, по порядку:
1) Меня не устраивает perf для Hashtable на c#. По моим данным она в 10 раз ниже аналога на java
2) C Dictionary все ок — производительность что надо. Но проблема с thread-safe которую можно решить с помощью ReaderWriterLock. Но тогда он станет еще медленнее чем Hashtable. Не ок.
3) У java есть Hashmap and ConcurrentHashmap (добавленные соотвественно в 1 и 1.5[это 2004 год,!]), которые работают довольно быстро в отличии от продукта Сатьи и в которых решена проблема thread safe.
В итоге мне придется делать свою синхронизации для Dictionary, потому что какой-то молодец додумался реализовать нечто подобное только в 4 net.
А про то как работает GC в CLR я вообще молчу — тут нужна отдельная ветка с разбором всего и вся.
Ну вот и объясните мне как со всеми этими бесконечными косяками С# и Шарепоинт станут Великими? Что об этом говорят ваши Евангилисты?
Здравствуйте, mapnik, Вы писали:
M>Но тогда он станет еще медленнее чем Hashtable. Не ок.
Ты пробовал? Или так, теоретизируешь?
M>3) У java есть Hashmap and ConcurrentHashmap (добавленные соотвественно в 1 и 1.5[это 2004 год,!]), которые работают довольно быстро в отличии от продукта Сатьи и в которых решена проблема thread safe.
Про ConcurrentDictionary и CoreFX ты почему мимо ушей пропустил? Не вписывается в теорию?
Здравствуйте, mapnik, Вы писали:
M>Вы угараете надо мной что ли? В какой реальности этот CoreFX может заменить скажем .net 3.5 на машине кастомера? Не смешно
Ну, если тебе соображалки не хватает, то расшифрую. В CoreFX есть исходник ConcurrentDictionary с либеральной лицензией. Копируешь этот исходник и его зависимости в свой проект и собираешь под 3.5.
Здравствуйте, tofox2, Вы писали:
M>>И нет я не могу использовать ConcurrentDictionary — мне нужно поддерживать версии .net < 4. T>несложно самому обернуть Dictionary блокировками
Так как это сделано в ConcurrentDictionary — довольно сложно.
Здравствуйте, mapnik, Вы писали:
НС>>Кто тебе такой бред сказал?
M>Вы документацию производителя вообще читаете? Впрочем зачем это шарепоинт-программистам, это же не модно — читать.
молодцы, оправдываете назначение раздела. а я уж испугался что здесь теперь начнут решать скучные технические проблемы
Здравствуйте, mapnik, Вы писали:
M>Здравствуйте, Yoriсk, Вы писали:
M>Ок, по порядку: M>1) Меня не устраивает perf для Hashtable на c#. По моим данным она в 10 раз ниже аналога на java
Вот это упёртость, внушает!
M>2) C Dictionary все ок — производительность что надо. Но проблема с thread-safe которую можно решить с помощью ReaderWriterLock. Но тогда он станет еще медленнее чем Hashtable. Не ок.
lol
M>3) У java есть Hashmap and ConcurrentHashmap (добавленные соотвественно в 1 и 1.5[это 2004 год,!]), которые работают довольно быстро в отличии от продукта Сатьи и в которых решена проблема thread safe.
lol
M>Ну вот и объясните мне как со всеми этими бесконечными косяками С# и Шарепоинт станут Великими? Что об этом говорят ваши Евангилисты?
А всё же, что вы скажете насчёт того что java сливает
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Ну, если тебе соображалки не хватает, то расшифрую. В CoreFX есть исходник ConcurrentDictionary с либеральной лицензией. Копируешь этот исходник и его зависимости в свой проект и собираешь под 3.5.
Зачем мне умножать количество индусского кода в проекте? У меня и так его весь дотНет.
Я лучше уж тогда напишу нормальную реализацию собственными силами. Просто это время, которое можно было бы потратить на более интересные вещи. Вот так жизнь и проходит мимо
Здравствуйте, mapnik, Вы писали:
Y>>Вот я и спрашиваю: а в чём, собственно, разница?
M>Ок, по порядку: M>1) Меня не устраивает perf для Hashtable на c#. По моим данным она в 10 раз ниже аналога на java
Про Dictionary мы выяснили: его аналог на java — HashMap работает примерно с такой же скоростью.
А какой аналог Hashtable в java и где "данные"?
Здравствуйте, mapnik, Вы писали:
M>2) C Dictionary все ок — производительность что надо. Но проблема с thread-safe которую можно решить с помощью ReaderWriterLock. Но тогда он станет еще медленнее чем Hashtable. Не ок.
— Используете не подходящие конструкции языка из доисторических времен.
— Меряете производительность с помощью, DateTime, вместо того, чтобы взять профайлер, который, BTW, вам расскажет в чем проблема.
— Когда вам советуют использовать Dictionary, ваш изначальный код вдруг обрастает требованиям к многопоточности, с непоколибимой уверенностью, что вы уже и ее померяли и увидели просадку.
Здравствуйте, mapnik, Вы писали:
M>Ну вот и объясните мне как со всеми этими бесконечными косяками С# и Шарепоинт станут Великими? Что об этом говорят ваши Евангилисты?
Кэп: как только программисты начнут учить матчасть и перестанут использовать легаси-фреймворки (.net 3.5? 2015й? Серьёзно???).
Ну, т.е. никогда
По сабжу: хотите поддерживать легаси — ilspy в жубы и самостоятельно переписываем свежедобавленные (всего-то 5 лет прошло) плюшки. Не хотим — не поддерживаем.
В чём проблема-то?
Здравствуйте, Sinix, Вы писали:
S>Кэп: как только программисты начнут учить матчасть и перестанут использовать легаси-фреймворки (.net 3.5? 2015й? Серьёзно???). S>Ну, т.е. никогда
1 — учить матчасть — это вы скажите индусам или пакистанцам (или австралам?) которые писали дотНет. Версия concurrent dictionary появилась через 6 лет после аналога в java. Нормально так да?
2 — "перестанут использовать легаси-фреймворки" — это продакшен друг мой. Некоторые кастомеры еще сидят на 2-ке (вы ее в силу вашего молодого возраста верно и не помните). А некоторые кастомеры еще сидят на java 1.6. Это реальный мир друг мой, а не россыпь рекламных буклетов от MS.
S>По сабжу: хотите поддерживать легаси — ilspy в жубы и самостоятельно переписываем свежедобавленные (всего-то 5 лет прошло) плюшки. Не хотим — не поддерживаем. S>В чём проблема-то?
Да не нужен никакой ilspy. Просто нужно сделать нормальную реализацию самому и делов-то. Конечно вы этого не поймете — вы же у нас (и ваши друзья которые активно восхвалют Джеффри и Мадса вместе с вами) яркий framework developer, один из тех для кого Баллмер пританцовывал в свое время.
Просто руки опускаются. Одну кривость исправишь, тут же другая вылезает. Я ожидал что CLR будет нормальной платформой которая поможет мне сфокусироваться на создании хорошего продукта. Вместо это я должен патчить ее повсюду.
Здравствуйте, mapnik, Вы писали:
M>1 — учить матчасть — это вы скажите индусам или пакистанцам (или австралам?) которые писали дотНет. Версия concurrent dictionary появилась через 6 лет после аналога в java. Нормально так да?
Нет. Учить матчасть — это в том числе самостоятельно решать проблемы, а не обзывать других индусами, т.к. они не сделали это за вас. Там ещё много всего, но начать стоит именно с этого.
M>2 — "перестанут использовать легаси-фреймворки" — это продакшен друг мой. Некоторые кастомеры еще сидят на 2-ке (вы ее в силу вашего молодого возраста верно и не помните). А некоторые кастомеры еще сидят на java 1.6. Это реальный мир друг мой, а не россыпь рекламных буклетов от MS.
Кэп: за редчайшими исключениями типа использования недокументированных нюансов переезд с 2.0 на 4.6 делается без перекомпиляции. Правкой appconfig. Вопрос лени и квалификации разработчиков.
С 1.1 — с ходу не вспомню, поддерживается запуск без перекомпиляции, или нет. Мы в своё время не страдали и просто перешли с колёс на бету 2.0, как только go live вышла.
M>Да не нужен никакой ilspy. Просто нужно сделать нормальную реализацию самому и делов-то.
Кэп #2: как самостоятельно напишете что-то сравнимое — приходите. Там кроме пафоса с апломбом ещё знания нужны, вот незадача
Здравствуйте, mapnik, Вы писали:
M>Здравствуйте, Sinix, Вы писали:
это вы скажите индусам или пакистанцам (или австралам?) которые писали дотНет. Версия concurrent dictionary появилась через 6 лет после аналога в java. Нормально так да?
M>Просто руки опускаются. Одну кривость исправишь, тут же другая вылезает. Я ожидал что CLR будет нормальной платформой которая поможет мне сфокусироваться на создании хорошего продукта. Вместо это я должен патчить ее повсюду.
Понимаете, просто .NET как раз и младше джавы примерно на 6 лет, java появилась в 95-ом, а .net в 2001-ом.. и это касается не только CLR, с фрэймворками, build инструментами тоже самое, обычно появляется фрэймворк для джава, а через несколько лет портируется на .NET или создают библиотеку с похожим функционалом.. например NUnit, NHibernate, Spring.NET...
Здравствуйте, Sinix, Вы писали:
S>Нет. Учить матчасть — это в том числе самостоятельно решать проблемы, а не обзывать других индусами, т.к. они не сделали это за вас. Там ещё много всего, но начать стоит именно с этого.
Давайте я прибегну к аллегории, может быть так вам станет яснее.
Представьте себе что вы архитектор. Не московский c#-"архитектор" полугомосексуал в прозрачном свитерке, а самый настоящий американский архитектор 20-30-х годов 20-го века. Словно Хэнк Риэрдан в архитектуре (не буду вас утомлять деталями, кто этот персонаж). И вам нужно спроектировать Эмпайр-Стейт-Билдинг. В берете чертежный набор чтобы сделать свою работу и что же вы видите? Циркули все погнуты, сломаны или недоделаны, линейки все косы и кривые, а карандаши не чертят. Вы в гневе идете к производителю и говорите — это что такое? У меня работа стоит! А производитель вам отвечает — вам нужно выпрямить все циркули самому, выточить все новые линейки самому, а карандаши ну зачем они вам? Ведь люди в Азии рисуют углем вы то чем хуже? Вы им бросите в гневе — ваш инструмент гавно! А они вам "Учить матчасть — это в том числе самостоятельно решать проблемы, а не обзывать других индусами, т.к. они не сделали это за вас. Там ещё много всего, но начать стоит именно с этого.".
А небоскреб из стекла и стали все еще не построен потому проектировать углем как-то знаете неудобно.
Вы поймите, я же не прошу какого-то чуда. Ну в java же все есть. Неужели даже скопировать нормально не могут?
S>Кэп #2: как самостоятельно напишете что-то сравнимое — приходите. Там кроме пафоса с апломбом ещё знания нужны, вот незадача
Да нет тут никакого пафоса и апломба. Просто потому что сделать лучше чем сейчас в вашем любимом framework может любой нормальный программист. Здесь нечем гордится. Это обыденность, на которую просто придется убить день. Не rocket science, совершенно обычная задача. Правда отчего MS на это шесть лет потребовалось. Вот незадача. Хотя чем я удивляюсь в очередной раз?
Здравствуйте, mapnik, Вы писали:
M>Давайте я прибегну к аллегории, может быть так вам станет яснее.
Кривая аналогия. Проблема не в инструментах.
Проблема в том, что вы сели в капитанское кресло аэробуса и по громкой связи требуете от общественности боинг. Дескать, летать нельзя: штурвал утратили, ручку шасси сломали, форточки не те, а РУД вообще страшно сказать — автомат. Переучивайтесь.
Ну, или не лезьте туда, куда душа не лежит. Ругаться-то зачем?
M>Вы поймите, я же не прошу какого-то чуда. Ну в java же все есть. Неужели даже скопировать нормально не могут?
В шарпе тоже есть. Только вы просите точный аналог явы, иначе типа не считается.
M>Да нет тут никакого пафоса и апломба. ... Это обыденность, на которую просто придется убить день.
Я ж не зря писал про что-то сравнимое. Посмотрите на устройство TryAddInternal/TryUpdate, особенно на веточки с s_isValueWriteAtomic==false и FEATURE_RANDOMIZED_STRING_HASHING и не несите чепухи. Про нюансы с tables/nodes даже начинать не буду.
Здравствуйте, mapnik, Вы писали:
M>Именно поэтому тема находится в СВ.
Место этой теме — в помойке, ты себя слишком высоко оцениваешь.
T>>Заменить Hashtable на Dictionary<int, float> M>Хотя ваш совет абсолютно правилен, этого нельзя сделать по некоторым причинам .
Да вообще никаких причин нет — это ты пришёл сюда с апломбами жабиста и пытаешься с какими-то искусственными ограничениями обыграть .NET;
Твои цели вообще непонятны — ты не проблемы решаешь, а именно понтуешься — смотришься как быдлятник, которому в табло мало засвечивали.
Ты уясни одну вещь: нам вообще на тебя на****ть — будь ты хоть лисповец или смоллтоковец. Хочешь решать проблемы на C# — подымай реальную задачу и спрашивай.
M>Хочу услышать их мнение .
Не хочешь, просто тупо гнёшь "моя жабка круче дотнета". Я с тобой даже спорить не буду, но ты КАК ТРОЛЬ тратишь время людей на препирания по бестолковейшему вопросу.
Нужен хэш — бери Dictionary и не выёживайся. И только когда у тебя возникнут _реальные_ проблемы с производительностью, тогда пересматривай решение (возможно, что и хэш — такой же бестолковый выбор, как и вся твоя тема).
За годы писания на дотнете я вообще никогда не сталкивался с тем, что грамотно выбранная коллекция мешала производительности — учись, жабкин!
Здравствуйте, mapnik, Вы писали:
M>Господа, M>Есть следующий (сильно упрощенный код ввиду публичного рассмотрения) c# код M>Как видите преимущество в производительности JVM в данном коде примерно на порядок (в 10 раз).
M>Что я делаю не так? Может быть где-то ошибка в коде? Если нет, то как ускорить C# код хотя бы до уровня JVM? M>Надеюсь на помощь господ, умудренных опытом в C#. Спасибо
Я мало умудрен опытом C#, поэтому вопрос не про язык программирования.
Зачем тебе большая скорость добавления в Hash? Может лучше взять список с константным добавлением? Ты бы определился с данными, что у тебя чаще вставка или поиск, и нужен ли тебе константный поиск.
Для меня твой вопрос звучит так: Гвоздь лучше забивается плоскогубцами чем отверткой. Действительно ли плоскогубцы лучше чем отверка? Если нет то как правильно забивать гвоздь отверткой?
Здравствуйте, Igore, Вы писали:
I>Зачем тебе большая скорость добавления в Hash? Может лучше взять список с константным добавлением? Ты бы определился с данными, что у тебя чаще вставка или поиск, и нужен ли тебе константный поиск.
Вставка в Hash table в лучшем случае O(1), в худшем O(n).
Ну я надеялся что программисты из MS нашли хорошую хэш-функцию и hashtable не вырождается в LinkedList сразу же.
Впрочем глядя на шарепоинт-программистов с блестящими глазами я уже в этом не уверен .
I>Для меня твой вопрос звучит так: Гвоздь лучше забивается плоскогубцами чем отверткой. Действительно ли плоскогубцы лучше чем отверка? Если нет то как правильно забивать гвоздь отверткой?
Тема чистый троллинг, я согласен. Но как весело смотреть на всю это "разгневанную секту" c#-программистов. Тест который я привел просто не укладывается в их промытые маркетингом мозги. Have a fun!
* Первый тест был на java1.8.0_05/win64 — java уступила в скорости неоптимальной версии C# Я подумал: jre не та...
* Второй тест на последней версии доступной с сайта — в некоторых итерациях почти догоняет оптимизированню версию, но в основном всё равно уступает неоптимальной — повидимому сказывается работа GC
(посмотреть можно тут: http://rsdn.ru/forum/flame.comp/6096755.1
) Я подумал: может дело в винде?...
* Третий тест — debian 7.8 wheezy/openjdk 1.7 (увы, это единственное что доступно из репозитория) — результат аналогичен первому тесту.
В принципе возможно (потому что у меня нет возможности это проверить, ибо лень), что oracle java 8 последней версии да на линухе покажет заявленные результаты... но слабо верится.
Какая-то черешка того... в принципе быстрый уход из темы её автора даже намекает какая именно
Здравствуйте, Sinix, Вы писали:
S>>Какая-то черешка того... в принципе быстрый уход из темы её автора даже намекает какая именно S>Не надо спорить. Автор откровенно троллит.
Троллить это нормально, а вот делать это с очень... противоречивыми данными как минимум непорядочно.
Здравствуйте, Somescout, Вы писали:
S>Троллить это нормально, а вот делать это с очень... противоречивыми данными как минимум непорядочно.
Скорее всего данные реальные, фаза луны так сложилась. Как пример — недавние похожие наезды на шарп в этом топике
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Somescout, Вы писали:
S>>Троллить это нормально, а вот делать это с очень... противоречивыми данными как минимум непорядочно. S>Скорее всего данные реальные, фаза луны так сложилась. Как пример — недавние похожие наезды на шарп в этом топике
и дальше по ветке. Без автовекторизации (которую уложить в жёсткий лимит JIT — задача та ещё) — баш на баш.
Не уверен. Дело в том что подобная оптимизация по идее делается JIT'ом, а значит первые проходы по циклу должны быть дольше, чем последующие. Что видно из натестированного мной. Я бы вообще предположил, что в одной из версий jre8 добавили оптимизацию, которая специализирует коллекции (и словари) если там используются только примитивные типы — т.е. делается то же самое что при переходе на generic Dictionary в C#, но без гарантий, зависимо от jit'а.
Строго говоря — нет.
В Hashtable нет ни volatile read/write, ни memory barriers, т.е. вполне возможно зачитка по уже имеющемуся ключу еще не вставленного значения или же наоборот: зачитка ключа от уже удалённого значения.
Т.е. ситуация, когда мы не можем найти элемент, который "только что добавлен из другого потока", или нашли и прочитали элемент, который "уже удалён другим потоком" — это вполне нормальный сценарий для конкурентного доступа. Но когда мы по валидному ключу читаем невалидное значение, то это уже натуральный ууупппсс. ))
M>2) Я пробовал прогонять код для более короткого цикла (напр. 100000) и clr и jvm имеют одну производительность. Такое ощущение что CLR GC не справляется. Это также подтверждается вызовом GCSettings.LatencyMode на LowLatency. Цифры сразу взлетают вверх.
Это боксинг. Твоя псевдопотокобезопасность Hashtable зиждется на том, что ключи и значения в таблице представлены типом-ссылкой, чтение и запись которых атомарны на поддерживаемых CRL платформах. В общем же случае как в Dictionary<> в дотнете или аналогичном решении на Java, где ключ или значение не влезают в машинное слово — никаких потокобезопасных решений без специальных для этого техник (типа read/write lock, даже пусть их ligh-варианта на спин-локах) нет и быть не может. Всё, что нельзя записать/прочитать через Interlocked.Exchange (или его аналог) — всё идет мимо кассы.
Кароч, сама постановка задачи изначально ошибочна — нельзя требовать того, что быть не может.
Здравствуйте, vdimas, Вы писали:
M>>1)Hashtable is thread safe. V>Строго говоря — нет. V>В Hashtable нет ни volatile read/write, ни memory barriers, т.е. вполне возможно зачитка по уже имеющемуся ключу еще не вставленного значения или же наоборот: зачитка ключа от уже удалённого значения.
Открываем System.Collections.Hashtable декомпилятором и видим:
private volatile int version;
private volatile bool isWriterInProgress;
Опять говоришь о том, что не знаешь.
Не надоело позориться?
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
M>>>1)Hashtable is thread safe. V>>Строго говоря — нет. V>>В Hashtable нет ни volatile read/write, ни memory barriers, т.е. вполне возможно зачитка по уже имеющемуся ключу еще не вставленного значения или же наоборот: зачитка ключа от уже удалённого значения. WH>Открываем System.Collections.Hashtable декомпилятором и видим: WH>
Да, в дотнете volatile означает барьеры памяти. Думал, как в плюсах это является инструкциями только компилятору.
Барьер не полный, в случае с дотнетом:
Термин volatile read означает чтение памяти в сочетании с созданием accure fence.
Accure fence гарантирует что инструкции, стоящие после барьера, не будут перемещены в позицию до барьера.
Обратное гарантируется Release fence, т.е. volatile write.
Посмотрел еще раз внимательнее на чтение:
private bucket[] buckets; // без volatile
...
bucket[] lbuckets = buckets;
...
do
{
int currentversion;
int spinCount = 0;
do {
// this is violate read, following memory accesses can not be moved ahead of it.
currentversion = version;
b = lbuckets[bucketNumber];
...
} while ( isWriterInProgress || (currentversion != version) );
Т.е. операция b = lbuckets[bucketNumber] является независимой от обращения к полям isWriterInProgress и currentversion, т.е. может произойти уже после их чтения. Барьер по чтению как раз это разрешает.
После этого while идет проверка на то, что найденный ключ b.key соответствует искомому.
В момент чтения b = lbuckets[bucketNumber] без всяких барьеров можно прочитать в поля bucket значения из памяти в произвольном порядке, например прочитать в b.val null, в то время как b.key и b.hash_coll будут еще валидными.
Здравствуйте, vdimas, Вы писали:
V>В момент чтения b = lbuckets[bucketNumber] без всяких барьеров можно прочитать в поля bucket значения из памяти в произвольном порядке, например прочитать в b.val null, в то время как b.key и b.hash_coll будут еще валидными.
В этом случае сработает вот это условие
isWriterInProgress || (currentversion != version)
И значение будет считано ещё раз.
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, mapnik, Вы писали:
M>Я не совсем точно сформулировал свой вопрос. Я хотел бы понять у C# и шарепоинт-программистов, почему clr так легко проседает на таком простом кусочке кода по отнашению к JVM . Именно поэтому тема находится в СВ. M>Хочу услышать их мнение .
Не совсем ясно, как ты хочешь получить разницу между clr и jvm, сравнивая __разные__ алгоритмы
Здравствуйте, mapnik, Вы писали:
M>Здравствуйте, Yoriсk, Вы писали:
Y>>Еще раз, по порядку: cравниваются реализации на Java и С#. Вы говорите, что реализация на HashMap, который thread-safe только в случае immutable на java вас устраивает, а на Dictionary на .net — нет. Поэому в Dictionary нужен ReaderWriterLock, а в HashMap, ... какая-то аналогичная конструкция на java(ReadWritLock?). Y>>Вот я и спрашиваю: а в чём, собственно, разница?
M>Ок, по порядку: M>1) Меня не устраивает perf для Hashtable на c#. По моим данным она в 10 раз ниже аналога на java
Краткий пересказ того, что ты не смог правильно перевести:
1 Hashtable не является аналогом HashMap
2 Близким аналогом HashMap является Dictionary<>
Здравствуйте, WolfHound, Вы писали:
V>>В момент чтения b = lbuckets[bucketNumber] без всяких барьеров можно прочитать в поля bucket значения из памяти в произвольном порядке, например прочитать в b.val null, в то время как b.key и b.hash_coll будут еще валидными. WH>В этом случае сработает вот это условие WH>
Я как раз указал на то, что коль содержимое this.buckets не является volatile, а операция b = lbuckets[bucketNumber] независима по данным с isWriterInProgress || (currentversion != version), то процессор имеет полное право эти операции переупорядочить. Посмотри внимательно еще раз. Обращение к isWriterInProgress и currentversion идет по чтению:
Accure fence гарантирует что инструкции, стоящие после барьера, не будут перемещены в позицию до барьера.
Но обратное разрешено.
Т.е. косяк есть и не срабатывает он лишь по той причине, что в текущих процах x86 и AMD64 нет разделения на Release fence и Accure fence, т.е. барьер всегда только один — полный Strict fence (оно же std::memory_order_seq_cst в С++11). Зато в Итаниуме и PowerPC барьеры разные.