clr perf problem
От: mapnik США http://www.hooli.xyz/
Дата: 30.06.15 07:11
Оценка: -1 :)))
Господа,

Есть следующий (сильно упрощенный код ввиду публичного рассмотрения) 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();
        }
    }
}


и app.config для него
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <runtime>
    <gcConcurrent enabled="false"/>
    <gcServer enabled="true" />
  </runtime>
</configuration>


И 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

Java:
m[100] = 0.01
Took: 0.362s
m[100] = 0.01
Took: 0.376s
m[100] = 0.01
Took: 0.395s
m[100] = 0.01
Took: 0.225s
m[100] = 0.01
Took: 0.513s
m[100] = 0.01
Took: 0.22s
m[100] = 0.01
Took: 0.684s
m[100] = 0.01
Took: 0.231s
m[100] = 0.01
Took: 1.266s
m[100] = 0.01
Took: 0.241s

Как видите преимущество в производительности JVM в данном коде примерно на порядок (в 10 раз).

Что я делаю не так? Может быть где-то ошибка в коде? Если нет, то как ускорить C# код хотя бы до уровня JVM?
Надеюсь на помощь господ, умудренных опытом в C#. Спасибо
Re: clr perf problem
От: tofox2 Россия  
Дата: 30.06.15 07:41
Оценка:
Здравствуйте, mapnik, Вы писали:

M>Что я делаю не так? Может быть где-то ошибка в коде? Если нет, то как ускорить C# код хотя бы до уровня JVM?

M>Надеюсь на помощь господ, умудренных опытом в C#. Спасибо

Заменить Hashtable на Dictionary<int, float>
Re[2]: clr perf problem
От: mapnik США http://www.hooli.xyz/
Дата: 30.06.15 07:48
Оценка:
Здравствуйте, tofox2, Вы писали:

T>Заменить Hashtable на Dictionary<int, float>


Хотя ваш совет абсолютно правилен, этого нельзя сделать по некоторым причинам .

Я не совсем точно сформулировал свой вопрос. Я хотел бы понять у C# и шарепоинт-программистов, почему clr так легко проседает на таком простом кусочке кода по отнашению к JVM . Именно поэтому тема находится в СВ.
Хочу услышать их мнение .
Отредактировано 30.06.2015 8:38 a_g_99 . Предыдущая версия .
Re: clr perf problem
От: Somescout  
Дата: 30.06.15 07:50
Оценка: 2 (1) +4
Здравствуйте, mapnik, Вы писали:

M>Что я делаю не так? Может быть где-то ошибка в коде? Если нет, то как ускорить C# код хотя бы до уровня JVM?


Hashtable hashtable = new Hashtable(n);


  Результат
m[100] = 0,01
Took: 2,2621291s
m[100] = 0,01
Took: 2,1791195s
m[100] = 0,01
Took: 2,2051228s
m[100] = 0,01
Took: 2,2191271s
m[100] = 0,01
Took: 2,2661294s
m[100] = 0,01
Took: 2,0771193s
m[100] = 0,01
Took: 2,1621237s
m[100] = 0,01
Took: 1,9841147s
m[100] = 0,01
Took: 2,4391384s
m[100] = 0,01
Took: 2,2581295s


var hashtable = new System.Collections.Generic.Dictionary<int, double>(n);


  Результат
m[100] = 0,01
Took: 0,1880258s
m[100] = 0,01
Took: 0,2429998s
m[100] = 0,01
Took: 0,2470129s
m[100] = 0,01
Took: 0,2510149s
m[100] = 0,01
Took: 0,249014s
m[100] = 0,01
Took: 0,2530143s
m[100] = 0,01
Took: 0,2550155s
m[100] = 0,01
Took: 0,2510141s
m[100] = 0,01
Took: 0,2500144s
m[100] = 0,01
Took: 0,2510148s


Подозреваю проблема в боксинге.
ARI ARI ARI... Arrivederci!
Re[3]: Гм...
От: Somescout  
Дата: 30.06.15 08:11
Оценка:
Здравствуйте, mapnik, Вы писали:

M>Я не совсем точно сформулировал свой вопрос. Я хотел бы понять у сC# и шарепоинт-программистов, почему clr так легко проседает на таком простом кусочке кода по отнашению к JVM . Именно поэтому тема находится в СВ.

M>Хочу услышать их мнение .

C:\Temp>java hashtablebenchmark.Hashtablebenchmark  -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC -XX:+AggressiveOpts
m[100] = 0.01
Took: 15.03s
m[100] = 0.01
Took: 14.831s
m[100] = 0.01
Took: 10.032s
m[100] = 0.01
Took: 6.485s
m[100] = 0.01
Took: 7.296s
m[100] = 0.01
Took: 6.138s
m[100] = 0.01
Took: 7.199s
m[100] = 0.01
Took: 8.847s
m[100] = 0.01
Took: 3.847s
m[100] = 0.01
Took: 5.502s


Это на той же машине, что и в http://rsdn.ru/forum/flame.comp/6096652.1
Автор: Somescout
Дата: 30.06.15
ARI ARI ARI... Arrivederci!
Re[3]: clr perf problem
От: Jack128  
Дата: 30.06.15 08:27
Оценка:
Здравствуйте, mapnik, Вы писали:

M>Я не совсем точно сформулировал свой вопрос. Я хотел бы понять у сC# и шарепоинт-программистов, почему clr так легко проседает на таком простом кусочке кода по отнашению к JVM . Именно поэтому тема находится в СВ.

M>Хочу услышать их мнение .

Может быть потому что это — говнокод, и никто не будет оптимизировать рантайм под него?
Re[4]: Гм...
От: mapnik США http://www.hooli.xyz/
Дата: 30.06.15 08:44
Оценка:
Здравствуйте, Somescout, Вы писали:

S>Это на той же машине, что и в http://rsdn.ru/forum/flame.comp/6096652.1
Автор: Somescout
Дата: 30.06.15


Вы не добавили аргумент -server. Это конечно моя ошибка, я так часто его использую что просто забыл написать про это
Re[2]: clr perf problem
От: mapnik США http://www.hooli.xyz/
Дата: 30.06.15 08:57
Оценка: -2 :))) :))) :))
Здравствуйте, Somescout, Вы писали:

S>
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. Цифры сразу взлетают вверх.
Re[5]: Гм...
От: Somescout  
Дата: 30.06.15 08:57
Оценка:
Здравствуйте, mapnik, Вы писали:

M>Вы не добавили аргумент -server. Это конечно моя ошибка, я так часто его использую что просто забыл написать про это


C:\Temp>"c:\Program Files\Java\jre8\bin\java.exe" hashtablebenchmark.Hashtablebenchmark  -Xmx3550m -Xms3550m -Xmn2g -Xss128k 
  -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC -XX:+AggressiveOpts -server
m[100] = 0.01
Took: 14.763s
m[100] = 0.01
Took: 15.381s
m[100] = 0.01
Took: 13.893s
m[100] = 0.01
Took: 11.663s
m[100] = 0.01
Took: 8.053s
m[100] = 0.01
Took: 7.803s
m[100] = 0.01
Took: 7.746s
m[100] = 0.01
Took: 4.668s
m[100] = 0.01
Took: 3.827s
m[100] = 0.01
Took: 4.049s

C:\Temp>"c:\Program Files\Java\jre8\bin\java.exe" -version
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)


Даже специально новую версию скачал:
c:\Temp>"c:\Program Files\Java\jre1.8.0_45\bin\java.exe" hashtablebenchmark.Hashtablebenchmark  -Xmx3550m -Xms3550m -Xmn
2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC -XX:+AggressiveOpts -server
m[100] = 0.01
Took: 9.318s
m[100] = 0.01
Took: 3.293s
m[100] = 0.01
Took: 6.128s
m[100] = 0.01
Took: 7.477s
m[100] = 0.01
Took: 0.734s
m[100] = 0.01
Took: 0.39s
m[100] = 0.01
Took: 0.641s
m[100] = 0.01
Took: 2.588s
m[100] = 0.01
Took: 3.285s
m[100] = 0.01
Took: 2.617s

c:\Temp>"c:\Program Files\Java\jre1.8.0_45\bin\java.exe" -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
ARI ARI ARI... Arrivederci!
Отредактировано 30.06.2015 9:00 Somescout . Предыдущая версия .
Re[3]: clr perf problem
От: Ночной Смотрящий Россия  
Дата: 30.06.15 09:14
Оценка: +2
Здравствуйте, mapnik, Вы писали:

M>1) Не могу использовать Dictionary. Он не thread-safe, а Hashtable is thread safe.


Кто тебе такой бред сказал? И то и другое — не thread safe. Оба поддерживают режим произвольного количества читателей. Наконец, есть действительно thread safe словарь — ConcurrentDictionary.
Re[4]: clr perf problem
От: mapnik США http://www.hooli.xyz/
Дата: 30.06.15 09:26
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Кто тебе такой бред сказал? И то и другое — не 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.
Re[5]: clr perf problem
От: Yoriсk  
Дата: 30.06.15 09:56
Оценка: +4
Здравствуйте, mapnik, Вы писали:

M>

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.


Но HashMap можно, а Dictionary — нет. Интересно.
Re[6]: clr perf problem
От: mapnik США http://www.hooli.xyz/
Дата: 30.06.15 10:07
Оценка: -1
Здравствуйте, Yoriсk, Вы писали:

Y>Ну совсем как HashMap:

Y>Но HashMap можно, а Dictionary — нет. Интересно.

Нет не совсем. Hashtable разрешает один writer вместе с multiple readers без locking, а Dictionary нет. Это именно мой сценарий использования. В Dictionary при таком варианте использования нужно использовать ReaderWriterLock, который делает его очень медленным.
Впрочем в CLR похоже все не быстрое.
Re[7]: clr perf problem
От: Ночной Смотрящий Россия  
Дата: 30.06.15 10:13
Оценка: +1 -1
Здравствуйте, mapnik, Вы писали:

M>Нет не совсем. Hashtable разрешает один writer вместе с multiple readers без locking, а Dictionary нет.


И HashMap — тоже нет.
Re[5]: clr perf problem
От: Ночной Смотрящий Россия  
Дата: 30.06.15 10:13
Оценка:
Здравствуйте, mapnik, Вы писали:

M>И нет я не могу использовать ConcurrentDictionary — мне нужно поддерживать версии .net < 4.


CoreFX? Не, не слышал.
Re[7]: clr perf problem
От: Ночной Смотрящий Россия  
Дата: 30.06.15 10:21
Оценка:
Здравствуйте, mapnik, Вы писали:

Тебе нужно перевести "If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally"?
Re[6]: clr perf problem
От: mapnik США http://www.hooli.xyz/
Дата: 30.06.15 10:22
Оценка: -1
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>CoreFX? Не, не слышал.


Вы угараете надо мной что ли? В какой реальности этот CoreFX может заменить скажем .net 3.5 на машине кастомера? Не смешно
Re[8]: clr perf problem
От: mapnik США http://www.hooli.xyz/
Дата: 30.06.15 10:32
Оценка: -1
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Тебе нужно перевести "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 в моем случае (это уже проверено). Тема появилась не от балды.
Re[7]: clr perf problem
От: Sharov Россия  
Дата: 30.06.15 10:33
Оценка:
Здравствуйте, mapnik, Вы писали:

M>Нет не совсем. Hashtable разрешает один writer вместе с multiple readers без locking, а Dictionary нет. Это именно мой сценарий использования. В Dictionary при таком варианте использования нужно использовать ReaderWriterLock, который делает его очень медленным.


1) ReaderWriterLockSlim
2) что мешает побенчить с 1)
Кодом людям нужно помогать!
Re[7]: clr perf problem
От: Yoriсk  
Дата: 30.06.15 10:57
Оценка:
Здравствуйте, 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?).

Вот я и спрашиваю: а в чём, собственно, разница?
Отредактировано 30.06.2015 10:59 Yoriсk . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.