Почему новый тип кортежа in.Net 4.0 ссылочный тип (класс), а не тип значения (структура)
кто-нибудь знает ответ и/или иметь мнение о ней?
поскольку кортежи обычно не были бы очень большими, я бы предположил, что для них было бы более целесообразно использовать структуры, чем классы. Что скажешь ты?
5 ответов:
Microsoft сделала все типы кортежей ссылочными типами в интересах простоты.
Я лично думаю, что это было ошибкой. Кортежи с более чем 4 полями очень необычны и должны быть заменены более типичной альтернативой в любом случае (например, тип записи в F#), поэтому только небольшие кортежи представляют практический интерес. Мои собственные тесты показали, что распакованные кортежи до 512 байт все еще могут быть быстрее, чем упакованные кортежи.
хотя эффективность памяти одна забота, я полагают, что доминирующей проблемой является накладные расходы сборщика мусора .NET. Распределение и сбор являются очень дорого на .NET, потому что его сборщик мусора не был очень сильно оптимизирован (например, по сравнению с JVM). Кроме того, по умолчанию .NET GC (рабочая станция) еще не была распараллелена. Следовательно, параллельные программы, использующие кортежи, останавливаются, поскольку все ядра борются за общий сборщик мусора, разрушая масштабируемость. Это не только главным, но, AFAIK, был полностью проигнорирован Microsoft, когда они рассмотрели эту проблему.
еще одна проблема-виртуальная отправка. Ссылочные типы поддерживают подтипы, и поэтому их члены обычно вызываются с помощью виртуальной отправки. Напротив, типы значений не могут поддерживать подтипы, поэтому вызов элемента является полностью однозначным и всегда может выполняться как прямой вызов функции. Виртуальная отправка очень дорого на современном оборудовании, потому что процессор не может предсказать, где программа счетчик будет в конечном итоге. JVM идет на многое, чтобы оптимизировать виртуальную отправку, но .NET этого не делает. Однако .NET обеспечивает выход из виртуальной отправки в виде типов значений. Таким образом, представление кортежей как типов значений может, опять же, значительно улучшить производительность здесь. Например, вызов
GetHashCode
на 2-кортеж миллион раз занимает 0,17 С, но вызов его на эквивалентной структуре занимает всего 0,008 с, т. е. тип значения на 20× быстрее, чем ссылочный тип.настоящий ситуация, когда эти проблемы производительности с кортежами обычно возникает в использовании кортежей в качестве ключей в словарях. Я на самом деле наткнулся на этот поток, перейдя по ссылке из вопроса переполнения стека F# работает мой алгоритм медленнее, чем Python! где авторская программа F# оказалась медленнее, чем его Python именно потому, что он использовал коробочные кортежи. Распаковка вручную с помощью рукописного
struct
тип делает его программу F# в несколько раз быстрее, и быстрее, чем Питон. Эти проблемы никогда бы не возникли, если бы кортежи были представлены типами значений, а не ссылочными типами...
причина, скорее всего, потому, что только меньшие Кортежи будут иметь смысл как типы значений, так как они будут иметь небольшой объем памяти. Более крупные кортежи (т. е. те, у которых больше свойств) фактически пострадают в производительности, так как они будут больше 16 байт.
вместо того, чтобы некоторые кортежи были типами значений, а другие-ссылочными типами и заставляли разработчиков знать, какие из них я бы предположил, что люди в Microsoft думали, что они все ссылочные типы было проще.
Ах, подозрения подтвердились! Пожалуйста, смотрите Дом Кортежа!--6-->:
первое важное решение, был ли для обработки кортежей либо в качестве ссылки или тип значения. Так как они неизменный в любое время вы хотите изменить значения кортежа, вы должны создайте новый. Если они ссылочные типы, это означает, что может будет много мусора генерируется, если вы меняем элементы в кортеже в a тугая петля. F# кортежи были ссылка типа, но было ощущение от команда, которую они могли бы реализовать повышение производительности, если два, и возможно, три, элемент кортежи были вместо этого используются типы значений. Некоторые команды, которые создал внутренние кортежи использовал значение вместо ссылочных типов, потому что их сценарии были очень чувствительный к созданию большого количества управляемых объекты. Они обнаружили, что с помощью значения тип дал им лучшую производительность. В наш первый проект кортежа спецификация, мы держали 2-, трех - и четырехэлементные кортежи в виде типы значений, а остальные - ссылочный тип. Однако, во время встреча по дизайну, которая включала представители других языков было решено, что это " раскол" дизайн будет запутанным, из-за немного отличается семантика между два типа. Последовательность в поведении и дизайн был определен, чтобы быть более высокий приоритет, чем потенциал прирост производительности. Исходя из этого входной сигнал, мы изменили конструкцию так, что все Кортежи ссылочный тип, хотя мы попросили команду F# сделать некоторые исследования, чтобы найти если он испытал ускорение при использовании тип значения для некоторых размеров кортежей. Это был хороший способ проверить это, так как его компилятор, написанный на F#, был a хороший пример большой программы, которая используются кортежи в различных сценариях. В конце концов, команда F# обнаружила, что это не получил улучшения производительности когда некоторые кортежи были типами значений вместо ссылочных типов. Это сделано нам чувствовать себя лучше о нашем решении используйте ссылочные типы для кортежа.
для 2-кортежей по-прежнему всегда можно использовать KeyValuePair
из более ранних версий общей системы типов. Это тип значения. небольшое уточнение к статье Мэтта Эллиса будет заключаться в том, что разница в семантике использования между ссылочными и ценностными типами только "незначительна", когда действует неизменность (что, конечно же, будет иметь место здесь). Тем не менее, я думаю, что было бы лучше в дизайне BCL не вводить путаницу наличия кортежа переход к ссылочному типу на некотором пороге.
Я не знаю, но если вы когда-либо использовали F# кортежи являются частью языка. Если бы я сделал .dll и вернул тип кортежей было бы неплохо иметь тип, чтобы положить это. Теперь я подозреваю, что F# является частью языка (.Net 4) некоторые изменения в CLR были сделаны для размещения некоторых общих структур в F#
от http://en.wikibooks.org/wiki/F_Sharp_Programming/Tuples_and_Records
let scalarMultiply (s : float) (a, b, c) = (a * s, b * s, c * s);; val scalarMultiply : float -> float * float * float -> float * float * float scalarMultiply 5.0 (6.0, 10.0, 20.0);; val it : float * float * float = (30.0, 50.0, 100.0)