понедельник, марта 15, 2010

Так значимые или ссылочные?

Пишу я тут одну библиотеку, которая должна связывать 2 приложения, ничего друг о друге не знающих. Задачка не сложная, у библиотечки есть API, на вход методам которого подаются объекты, наследующие определённые интерфейсы, из этих объектов берутся нужные поля и данные передаются одному из приложений. Но суть не в этом. Внутри библиотеки я использую структуры, уповая на то, что значимые типы размещаются в стеке, а следовательно работать с ними быстрее, чем со сылочными, которые в куче. Вот и подумалось тут мне, есть метод, который возвращает проинициализированный некими значениями объект типа IInterface. Какая реализация метода отработает быстрее: в которой создаётся новый значимый тип или же ссылочный? Вроде как при значимом будет производиться боксинг, что довольно дорогое удовольствие, но в то же время для ссылочного компилятор генерирует callvirt вместо call, который тоже добавляет тормозов. В общем для проверки написал маленький тест.
Собственно, объявление типов:
  1. interface IInterface
  2. {
  3.   string field { get; }
  4. }
  5. struct Struct : IInterface
  6. {
  7.   public string field { get; set; }
  8. }
  9. class Class : IInterface
  10. {
  11.   public string field { get; set; }
  12. }
  13. static IInterface method1()
  14. {
  15.   return new Struct() { field = "0" };
  16. }
  17. static IInterface method2()
  18. {
  19.   return new Class() { field = "0" };
  20. }
* This source code was highlighted with Source Code Highlighter.
Ну и сам вызов:
  1. Stopwatch sw = new Stopwatch();
  2. sw.Start();
  3. for (int i = 0; i < 100000; i++)
  4. {
  5.   IInterface I = method1();
  6. }
  7. sw.Stop();
  8. Console.WriteLine("Test1: On struct elapsed: " + sw.Elapsed.ToString());
  9. sw.Reset();
  10. sw.Start();
  11. for (int i = 0; i < 100000; i++)
  12. {
  13.   IInterface I = method2();
  14. }
  15. sw.Stop();
  16. Console.WriteLine("Test1: On class elapsed: " + sw.Elapsed.ToString());
  17. Console.ReadLine();
* This source code was highlighted with Source Code Highlighter.
В результате получилось:
Test1: On struct elapsed: 00:00:00.0110243
Test1: On class elapsed: 00:00:00.0075070

В общем получилось, что боксинг медленнее виртуального вызова, но учитывая, что на 100 000 экземпляров разница составила 4 миллисекунды (это максимальная увиденная мной разница), с этим вполне себе можно жить.
Если же всётаки методы 1 и 2 будут возвращать не интерфейс, а структуру и класс соотвественно, то метод со структурой выполнится быстрее своего собрата.
Test1_1: On struct elapsed: 00:00:00.0042494
Test1_1: On class elapsed: 00:00:00.0067243

Оценивая полученные результаты, можно сказать,что работать со значимыми типами гораздо быстрее, а, порой и удобнее, но до тех пор, пока не требуется упаковывать эти значения. При боксинге значимые типы теряют своё преимущество в быстродействии.

Комментариев нет:

Отправить комментарий