Продажа квадроциклов, снегоходов и мототехники
second logo
Пн-Чт: 10:00-20:00
Пт-Сб: 10:00-19:00 Вс: выходной

+7 (812) 924 3 942

+7 (911) 924 3 942

Copy-on-write / Хабр

Познакомился я с этой темой на одном из собеседований, когда мне задали вопрос о том, что есть какая-то большая структура и сколько памяти будет занято, если переменную с экземпляром этой структуры присвоить другой переменной. Тогда, вспоминая о том, что происходит при взятие подстроки, я ответил, что объем памяти не изменится и ошибся. Ну и уже после собеседования полез читать о copy-on-write (далее COW).

В этой статье мы обсудим эту тему и она станет очередным пунктом в том, чем отличаются ссылочные типы от типов значений в языке Swift. Как и говорилось выше, одним из таких отличий является наличие функционала COW, о котором и будем говорить.

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

Однако можно задаться вопросом “а зачем копировать данные, если мы их не меняем?”. Действительно и COW как раз-таки отвечает на этот вопрос и говорит, что это не обязательно.

Проведем небольшой эксперимент:

func address(o: UnsafeRawPointer) { 
  print("address: \(Int(bitPattern: o))")
}
var arr1 = [1, 2, 3]
var arr2 = arr1
address(arr1)
address(arr2)

Как думаете, что выведет?
А выведет то, чего мы и хотели, задавая вопрос:

address: 105553133388704
address: 105553133388704

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

func address(o: UnsafeRawPointer) { 
  print("address: \(Int(bitPattern: o))")
}
var arr1 = [1, 2, 3]
var arr2 = arr1
arr2.append(4)
address(arr1) 
address(arr2)

address: 105553154755744
address: 105553135788672

Как можно заметить теперь ссылки ведут на разные области в памяти.

Что нам это дает?

Благодаря этим экспериментам становится ясно, что swift предоставляет механизм, который копирует поведение ссылочных типов на типы значений до первых изменений, такой механизм и называется COW. Это избавляет нашу программу от лишних копирований, тем самым улучшая производительность.

Увы, но даже не для всех структур из стандартной библиотеки он реализован, но точно реализован для основных типов, которые при копирование могут затратить большое количество ресурсов, а именно: String, Array, Dictionary и Set.

Становится очевидно, что для наших с вами собственных структур такой механизм тем более не предусмотрен, но — не беда, мы можем сделать его сами.

Собственный COW

final class Ref<T> { 
  var val: T
	
  init(v: T) { 
    val = v
  } 
}
struct Box<T> {
  var ref: Ref<T>
	
  init(x: T) { 
    ref = Ref(x)
  }
	var value: T { 
    get {
      ref.val 
    }
    set {
      if (!isKnownUniquelyReferenced(&ref)) {
        ref = Ref(newValue) 
      } else {
        ref. val = newValue
      }
    } 
  }
}

Одним из важных моментов этого кода является метод:

func isKnownUniquelyReferenced<T> (_ object: inout T?) -> Bool where T : AnyObject

Returns a Boolean value indicating whether the given object is known to have a single strong reference.

Данная реализация хранит наше value (в Box) одинаковым при переиспользование. Посмотрим на примере как этим пользоваться и каков будет результат. Для этого создадим нашу собственную структуру Test и один ее экземпляр.

struct Test {
  var x: Int
}
let val = Test(x: 5)
// Ну и используем наш Box
var box = Box(val)
var box2 = box
address(&box.value) 
address(&box2.value)

Как и планировалось, при выводе мы получим один и тот же адрес:

address: 140701847686488
address: 140701847686488

Источники

  • Understanding Swift Copy-on-write mechanism

  • What is copy on write?

  • Copy-on-write in Swift

SavePearlHarbor

Приветствую вас, любители ностальгических игр. Сегодня я хотел бы вернуться к тактическим играм прошлого. И если недавно я рассказывал про относительно «свежую» Операцию Silent Storm, то в этот раз хочу остановиться на мастодонте этого жанра: Jagged Alliance 2. Игра, вышедшая в 1999 году, для многих геймеров стала эталоном того, какими должны быть тактические стратегии.

JA2 я впервые увидел у друга в гостях. В то время он конкретно подсел на неё, часами напролёт пытаясь спасти народ Арулько от злобной королевы Дейдраны. Поэтому каждый день, заходя к нему, я тоже принимал участие в восстании в этой небольшой тропической стране. А так как он в то время кайфовал от Наутилус Помпилиус, во время игры мы до дыр заслушивали все их альбомы. Так, я стал не только фанатом Jagged Alliance 2, но и большим любителем Наутилуса, с которым она у меня теперь ассоциируется 🙂

После таких коллективных игровых партий у меня, естественно, появилось желание попробовать поспособствовать свержению Дейдраны самостоятельно, играя дома. Друг любезно предоставил мне не только диск, но и специальный выпуск журнала «Страна Игр», полностью посвящённый игре. Думаю, вам, настоящим олдфагам, будет интересно ознакомиться с ним, поэтому я попросил друга отыскать этот номер, после чего полностью отсканировал его. Ссылку на архив с журналом я выложил в телеграмм канале, переходи по ссылке и прикоснись к прошлому)

▍ Кто

Jagged Alliance 2 была создана трудами компании Sir-Tech Software и выпущена в 1999 году. В СНГ странах она больше известна как Jagged Alliance 2: Агония Власти. Локализацией занималась компания Buka, которая провела титаническую работу, создав отличный перевод и озвучку проекта. Даже на обложке игры было написано о привлечении 52 актёров озвучки, что даже в наше время отличный результат, а уж в конце девяностых годов…
Разработка игры началась вскоре после выхода первой части Jagged Alliance в 1994 года. Оригинальный продукт имел успех, поэтому разработчики хотели создать продолжение, которое сохранило бы уникальное сочетание пошаговой стратегии и элементов ролевой игры, исправив при этом её недостатки. Команда состояла из людей, уже имевших опыт создания пошаговых стратегий, под руководством Иэн Карри. Они работали над усовершенствованием графики, интерфейса и механики игры, делая её более привлекательной и доступной для более широкой аудитории.
Одной из главных задач было создание реалистичной и убедительной системы искусственного интеллекта противников, пытаясь заставить вести более разумно. При этом разработчики хотели сделать игру, бросающей вызов, но не удручающе сложной.
Jagged Alliance 2 была высоко оценена как критиками, так простыми игроками, и стала культовой классикой среди поклонников тактических стратегий.

Интересный факт: Кроме серии JA, компания Sir-Tech известна такой популярной в прошлом серией игр, как Wizardry, которая насчитывает 8 частей!

▍ Сюжет

Действие игры происходит в вымышленной стране Арулько, власть в которой захватила королева Дейдрана, установив военную диктатуру. Законный наследник – Энрико Чивалдори – был вынужден бежать за границу. Пытаясь высвободить страну из лап тирана, он нанимает вас, чтобы вы помогли повстанцам взять власть в стране. Игрок отправляет отряд профессиональных бойцов на территорию Арулько, чтобы свергнуть кровавого диктатора. Ваши наёмники атакуют небольшой городок Омерта на границе государства, и пламя революции вспыхивает с новой силой.

Во время выполнения задания отряд, двигаясь по стране, борется с армией Дейдраны в городах, на военных базах и радарах и прочих важных для страны объектах. На своём пути они встречают местных жителей и сопротивленцев, готовых к сотрудничеству. Получится ли освободить народ Арулько от гнёта королевы-самозванки? Теперь это зависит лишь от вас…

▍ Геймплей

Jagged Alliance 2 – это пошаговая стратегическая игра с ролевыми элементами. Игра начинается на глобальной карте Арулько, поделённой на клетки-сектора. По этой карте передвигаются как ваши отряды, так и вражеские войска. В данном стратегическом режиме всё идёт в реалтайме с возможностью перемотки времени или постановки на паузу. Для того, чтобы взаимодействовать с миром, вы просто открываете свой ноутбук с доступом в интернет (здесь вы сможете нанять новых бойцов или сделать заказ оружия, патрон и экипировки). Кроме того, именно тут записывается полученная информация и ведётся переписка по электронной почте.

В тот момент, когда ваш отряд оказывается в одном квадрате с вражескими войсками, осуществляется переход в тактический режим, загружается карта локации, на которой происходит бой (правда, никто не запрещает перейти на локацию и без боя). До тех пор, пока вы или противник не заметили друг друга, игра идёт в реальном времени, в противном случае – переключается в походовый режим. У каждого персонажа есть определённое количество очков действий (зависят от характеристик), которые он тратит в свой ход. На успешность ваших решений влияют не только навыки персонажа, но и его состояние (у усталого или раненого бойца падают боевые атрибуты).
Игрок управляет командой воинов, каждый из которых является личностью со своей предысторией, характеристиками, навыками и вкусами. Более того, в игре действует сложная система взаимоотношений между наёмниками. Многие бойцы имеют личную неприязнь или, наоборот, сильную любовь к своим коллегам, из-за чего меняется их боевая эффективность, уровень морали и скорость прокачки. Поэтому выбирать команду вы будете не только по визуальной симпатии или качествам бойца, но и по тому, насколько ваши наёмники могут сжиться друг с другом. К примеру, Иван и Игорь Долвич – родственники, поэтому являются примером хорошей команды. А поляк Анаболик терпеть не может майора Долвича, причём самому Ивану это совершенно до лампочки. Во время боя это не приносит никаких проблем, но вот от продления контракта Анаболик может отказаться.

В игре есть возможность нанимать воинов из разных организаций вроде A.I.M. (Association of International Mercenaries) или её аналога, в котором собраны довольно дешёвые бойцы со скромными характеристиками – M.E.R.C. (More Economic Recruiting Center). Помимо наёмников, к вашему отряду могут присоединиться и некоторые жители Арулько, причём большинство из них – абсолютно бесплатно!
Интересной возможностью, о которой я узнал далеко не сразу, является создание своего альтер эго в обличии бойца. Как в какой-нибудь ролевой игре, вы сможете выбрать портрет героя, его преимущества и недостатки, биографию, навыки и много что ещё!
В процессе игры можно тренировать своих наёмников и повышать их уровни, приобретать новое снаряжение и улучшать его. На экипировку можно устанавливать различные «обвесы»: сошки, глушители, прицелы, дополнительные бронелисты и т.д., тем самым повышая боевые свойства предмета. Более того, многие улучшения можно скрафтить самому! Например, можно собрать удлинитель, увеличивающий прицельную дальность на 10 метров (один тайл), из железной трубы, скотча и клея. И таких улучшений довольно много!

Цель игры – свергнуть диктатора Дейдрану. Для этого игрок должен захватывать важные объекты вроде городов, шахт, аэропортов, ПВО и т.д. Без боя, как вы понимаете, это сделать не получится. Ваш отряд пройдёт через десятки сражений, постепенно повышая своё мастерство, а вместе с ним и зарплату. Вы будете общаться с простыми гражданами, выполняя их поручения (по желанию) и налаживая экономическую стабильность вашей организации. Дело в том, что как на зарплаты, так и на закупку вооружений, патронов, топлива для транспорта, вам потребуются деньги. Мелкие суммы вы можете случайно найти на поле боя или в городах, а также как награду за задания, но это не позволит вам иметь стабильный доход. Отбив очередной город у войск тирана, вы можете обнаружить в нём серебряную или золотую шахту. В зависимости от отношения к вам жителей города, эти постройки начнут приносить стабильный доход. Но не стоит надеяться, что так будет вечно. Рано или поздно, шахта может истощиться!
Отбить город – это, конечно, хорошо, но стоит позаботиться и о его защите! Дейдрана обязательно пошлёт свои отряды, пытаясь вернуть под контроль утраченный населённый пункт. Для того, чтобы не оставлять в каждом городе своих наёмников, вы можете начать тренировать ополчение из местных жителей. Они, как и ваши солдаты, при дальнейшем обучении или в бою будут совершенствовать свои навыки и повышать характеристики.

Может показаться, что игра – лишь банальное отбивание секторов у вражеских войск, но это не так. Вы будете постоянно общаться с жителями городов узнавая от них полезную информацию, либо получая различные дополнительные задания. Выполнять их или нет – это на ваше усмотрение, но я могу сказать, что некоторые действительно интересные и оставляют приятные впечатления и достойную награду!

Заканчивая геймплейную тему, отмечу, что вам доступен не только реалистичный режим, но и фантастический. В нём, помимо вражеских войск, вы можете встретиться с гигантскими жуками, которые для плохо собранной партии являются довольно большим вызовом. Появятся они лишь в определённый момент игры, в одной из захваченных вами шахт (парализуя её работу), а затем каждую ночь будут нападать на город. Выбирать этот режим или нет – решать вам. От себя лишь скажу, что сражения с жуками помогут неплохо прокачать партию, а также позволят подзаработать денег. Помимо гигантских насекомых, добавятся новые NPC и изменятся некоторые реплики у уже существующих.

▍ Зачем играть?

Jagged Alliance 2 предлагает действительно увлекательный игровой опыт: большое количество тактических возможностей, множество уникальных персонажей со своими характерами и внутрипартийными отношениями, море оружия и экипировки, а также сбалансированную сложность. Всё это позволяет ей быть отличной тактикой и по сей день!

▍ Звуковое сопровождение

Саунд дизайн Jagged Alliance 2 выполнен на достойном уровне, ведь почти у каждого действия есть звук. Вы всегда поймёте, что происходит, услышав шаги или звук от рикошетирующей пули, а комментарии наёмников о ситуации на поле боя лишь способствуют ещё большему погружению. Кстати о них…

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

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

В целом звуковое сопровождение Jagged Alliance 2 прекрасно сочетается с геймплеем, помогает углубиться в игровой мир.

▍ Минусы

• Как и у любых культовых, но старых игр, главный минус – графика. К сожалению, это не одна из тех игр, которая хорошо сохранилась.
• Интерфейс немного перегружен.
• Кому-то может показаться довольно сложной.
• Туповатый искусственный интеллект, временами идущий на вас в лоб.

▍ Дополнения

Начну с того, что в наши дни я в принципе никому не советую начинать играть в Jagged Alliance 2 без фанатского патча 1.13, который добавляет в игру огромное количество нововведений. Это и поддержка современных разрешений экрана, и новая сложность, и более тонкая настройка каждого аспекта игры (от новой системы точности до системы умений), и немного подправленная экономика. Установив этот патч, даже старожилы получат удовольствие и новый опыт.

К игре было выпущено официальное дополнение Jagged Alliance 2: Unfinished Business (в СНГ Jagged Alliance 2: Цена Свободы). Это самостоятельное дополнение к классической пошаговой тактической RPG Jagged Alliance 2, выпущенное в 2000 году. Действие игры разворачивается сразу после событий Jagged Alliance 2 и рассказывает о группе наёмников, выполняющих новую миссию в соседней с Арулько стране – Траконе. Одним из заметных изменений в Unfinished Business является её линейность. В отличие от оригинальной игры, в которой была полная свобода действий, в UB вы должны добраться из «точки А» в «точку В», по пути расстреливая всех недругов. Здесь появились новое оружие и предметы, а также улучшения в игровом движке, добавлены наёмники (в результате их общее количество превысило 70). Валютно-денежные операции сведены до минимума, оружие теперь можно находить лишь на поле боя, а солдаты нанимаются не на определённый срок, а до победного конца. Не знаю, как вам, но мне такой подход к любимой игре не понравился, поэтому я в дополнение почти не играл.

Поскольку JA2 была воистину народной игрой с огромной армией фанатов, на неё выходило большое количество модов, порою весьма глобальных…

Одним из таких модов был Jagged Alliance 2: Wildfire, выпущенный в 2004 году (через 4 года после «Цены Свободы»). Благодаря своему качеству, этот мод получил поддержку со стороны издателя и начиная с 5-й версии, распространялся коммерчески, фактически став полноценным, официальным дополнением. Вы не представляете, каково было моё удивление, когда я, поехав за дисками на «Горбушку», увидел в одном из павильонов дополнение к игре, о котором ничего не слышал! Прошло так много лет, а я до сих пор помню, как, сидя в электричке по дороге домой, сотни раз изучал обратную сторону диска, предвкушая скорое возвращение в любимую игру!

Но что же привносит «новое» дополнение? Разработчики добавили поддержку больших разрешений экрана, благодаря которой Wildfire можно запускать в 1024х768. Далее по списку: доработан интерфейс, добавлено новое оружие и наёмники, подправлен баланс, улучшен звук. Я бы сказал, что это абсолютно типичное дополнение, которое не сильно выделяется, если бы не одно НО – почти все локации Арулько были пересмотрены. Кто-то посчитает это отсебятиной, но лично я считаю, что это действительно правильная переработка, делающая их архитектуру более логичной, правдоподобной и, главное, тактически интересной! Солдаты Дейдраны были по-новому «расставлены», занимая теперь более выигрышные позиции, а их интеллект подтянут. Мне кажется, после этих изменений бои стали более сложные и захватывающие, проверяющие ваш тактический талант. Кроме того, появился новый сюжет, который идёт параллельно со стандартным из «Агонии власти», дополняя и пересекаясь с ним, в результате чего в Арулько появляется третья сила – мафия. Думаю, в этом дополнении есть всё, чтобы быть отличным подарком для фаната оригинальной игры!

▍ Итог

Мне сложно советовать Jagged Alliance 2 новым игрокам, потому что по современным меркам игра довольно сложна, графика сохранилась плохо, а некоторые механики смотрятся архаично. Но если вас не остановят эти минусы, могу с уверенностью сказать, что вы получите интересный игровой опыт и с удовольствием проведёте десятки часов, освобождая бедную страну. А игроки, заставшие её в момент выхода, могут с удовольствием вернуться в ламповую атмосферу того времени, вновь погрузившись в любимую тактику. Для вашего удобства у себя на канале я выложил ссылку на архив с игрой и последним фанатским патчем.

Я играю в игры больше 25 лет и запомнил их именно такими: душевными и затягивающими, с увлекательными механиками и интерактивностью, без внутриигровой валюты и попыток быть чем угодно, но не игрой. В моём Telegram-канале тебя ждут не только обзоры на игры, но и актуальные новости, а также рассуждения о геймдеве. Подписывайся, будет интересно!​

Оптимизация

— что такое копирование при записи?

Книга Design Patterns: Elements of Reusable Object-Oriented Software Erich Gamma et al. ясно описывает оптимизацию копирования при записи (раздел «Последствия», глава «Прокси»):

Шаблон прокси вводит уровень косвенности при доступе к объект. Дополнительная косвенность имеет множество применений, в зависимости от вид прокси:

  1. Удаленный прокси может скрыть тот факт, что объект находится в другом адресном пространстве.
  2. Виртуальный прокси может выполнять оптимизацию, например создавать объект по требованию.
  3. Как прокси-серверы защиты, так и смарт-ссылки позволяют выполнять дополнительные вспомогательные задачи при доступе к объекту.

Есть еще одна оптимизация, которую шаблон Proxy может скрыть от клиент. Он называется копирование при записи и связан с созданием на требовать. Копирование большого и сложного объекта может быть дорогостоящим операция. Если копия никогда не изменялась, то нет необходимости нести эту стоимость. Используя прокси для отсрочки процесса копирования, мы убедиться, что мы платим цену за копирование объекта только в том случае, если он модифицированный.

Чтобы копирование при записи работало, ссылка на субъект должна учитываться. Копирование прокси не сделает ничего, кроме увеличения этой ссылки. считать. Только когда клиент запрашивает операцию, которая изменяет Тема действительно ли прокси копирует его. В этом случае прокси должен также уменьшить счетчик ссылок субъекта. Когда счетчик ссылок становится равным нулю, тема удаляется.

Копирование при записи может снизить стоимость копирования тяжеловесных объектов существенно.

Ниже приведена реализация Python оптимизации копирования при записи с использованием шаблона Proxy. Целью этого шаблона проектирования является предоставление суррогата другому объекту для управления доступом к нему.

Диаграмма классов шаблона Proxy:

Диаграмма объектов шаблона Proxy:

Сначала мы определяем интерфейс субъекта:

 import abc
Тема класса (abc.ABC):
    @abc.abstractmethod
    клон защиты (я):
        поднять NotImplementedError
    @abc.abstractmethod
    деф читать (сам):
        поднять NotImplementedError
    @abc.abstractmethod
    Запись по определению (я, данные):
        поднять NotImplementedError
 

Далее мы определяем реальный субъект, реализующий интерфейс субъекта:

 импортировать копию
класс RealSubject(Тема):
    def __init__(я, данные):
        self.data = данные
    клон защиты (я):
        вернуть копию. deepcopy(я)
    деф читать (сам):
        вернуть self.data
    Запись по определению (я, данные):
        self.data = данные
 

Наконец, мы определяем прокси, реализующий интерфейс субъекта и ссылающийся на реальный субъект:

 класс Прокси(Тема):
    def __init__(я, субъект):
        self.subject = тема
        пытаться:
            self.subject.counter += 1
        кроме AttributeError:
            self.subject.counter = 1
    клон защиты (я):
        return Proxy(self.subject) # совместное использование атрибутов (поверхностная копия)
    деф читать (сам):
        вернуть self.subject.read()
    Запись по определению (я, данные):
        если self.subject.counter >
1: self.subject.counter -= 1 self.subject = self.subject.clone() # копирование атрибута (глубокое копирование) self.subject.counter = 1 self.subject.write(данные)

Затем клиент может извлечь выгоду из оптимизации копирования при записи, используя прокси-сервер в качестве замены для реального субъекта:

 if __name__ == '__main__':
    x = Прокси (RealSubject ('foo'))
    x. write('бар')
    y = x.clone() # реальная тема используется совместно, а не копируется
    print(x.read(), y.read()) # полоса полоса
    утверждать, что x.subject является y.subject
    x.write('baz') # реальная тема копируется при записи, потому что она была опубликована
    print(x.read(), y.read()) # базовая панель
    утверждать, что x.subject не является y.subject
 

c++ — Как реализовать копирование при записи?

Я бы посоветовал, если кто-то хочет эффективно реализовать копирование при записи (для строк или чего-то еще), следует определить тип оболочки, который будет вести себя как изменяемая строка и будет содержать как обнуляемую ссылку на изменяемую строку (никакая другая ссылка на этот элемент никогда не будет существовать) и обнуляемая ссылка на «неизменяемую» строку (ссылки на которые никогда не будут существовать вне вещей, которые не будут пытаться их изменить). Оболочки всегда будут создаваться по крайней мере с одной из этих ссылок, не равных нулю; как только ссылка на изменяемый элемент когда-либо устанавливается на ненулевое значение (во время или после построения), она всегда будет ссылаться на одну и ту же цель.

В любое время, когда обе ссылки не равны нулю, ссылка на неизменяемый элемент будет указывать на копию элемента, которая была сделана через некоторое время после последней завершенной мутации (во время мутации ссылка на неизменяемый элемент может содержать или не содержать ссылку до значения до мутации).

Чтобы прочитать объект, проверьте, не является ли ссылка «изменяемый элемент» нулевой. Если это так, используйте его. В противном случае проверьте, не является ли ссылка «неизменяемый элемент» нулевой. Если это так, используйте его. В противном случае используйте ссылку «изменяемый элемент» (которая теперь будет не нулевой).

Чтобы изменить объект, проверьте, не является ли ссылка «изменяемый элемент» нулевой. Если нет, скопируйте цель ссылки на «неизменяемый элемент» и CompareExchange ссылку на новый объект в ссылку на «изменяемый элемент». Затем измените цель ссылки на «изменяемый элемент» и сделайте недействительной ссылку на «неизменяемый элемент».

Чтобы клонировать объект, если предполагается, что клон будет клонирован снова, прежде чем он будет изменен, извлеките значение ссылки «неизменяемый-элемент». Если он равен нулю, сделайте копию цели «изменяемый элемент» и CompareExchange ссылку на этот новый объект в ссылку на неизменяемый элемент. Затем создайте новую оболочку, ссылка на «изменяемый элемент» которой равна нулю, а ссылка на «неизменяемый элемент» является либо извлеченным значением (если оно не было нулевым), либо новым элементом (если оно было).

Чтобы клонировать объект, если ожидается, что клон будет видоизменен до того, как он будет клонирован, извлеките значение ссылки «неизменный-элемент». Если значение null, получить ссылку на «изменяемый элемент». Скопируйте цель любой извлеченной ссылки и создайте новую оболочку, чья ссылка «изменяемый элемент» указывает на новую копию, а ссылка «неизменный элемент» имеет значение null.

Два метода клонирования будут семантически идентичными, но выбор неправильного метода для данной ситуации приведет к дополнительной операции копирования. Если кто-то последовательно выбирает правильную операцию копирования, он получит большую часть преимуществ «агрессивного» подхода копирования при записи, но с гораздо меньшими затратами на многопоточность. Каждый объект, содержащий данные (например, строка), будет либо неразделяемым изменяемым, либо общим неизменяемым, и ни один объект никогда не будет переключаться между этими состояниями. Следовательно, при желании можно было бы устранить все «накладные расходы на многопоточность/синхронизацию» (заменив операции CompareExchange прямыми хранилищами) при условии, что ни один объект-оболочка не используется более чем в одном потоке одновременно. Два объекта-оболочки могут содержать ссылки на один и тот же неизменяемый держатель данных, но они могут не знать о существовании друг друга.

Обратите внимание, что при использовании этого подхода может потребоваться несколько больше операций копирования, чем при использовании «агрессивного» подхода. Например, если новая оболочка создается с новой строкой, и эта оболочка видоизменяется и копируется шесть раз, исходная оболочка будет содержать ссылки на исходный держатель строки, а неизменяемый — копию данных. Шесть скопированных оболочек будут просто содержать ссылку на неизменяемую строку (всего две строки, хотя, если исходная строка никогда не изменялась после создания копии, агрессивная реализация могла бы обойтись одной).

Разное

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *