2016-08-11 5 views
3

Я читаю от Apple documentation. Я думал, что знаю, когда выбрать тип значения и когда выбрать тип ссылки, но я вернулся к Swif101. В документации сказано:Описание описания и значений описания Apple с несколькими потоками

  • Типы значений: Эти данные будут использоваться в коде между несколькими потоками.
  • ссылочные типы: Вы хотите создать общедоступное, изменяемое состояние

ли не ссылочные типы также разделяемых между несколькими потоками? Какая разница в этих двух строках?

ответ

1

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

Соотношения типов немного сложнее. Да, как указывали другие, если вы передаете тип значения в качестве параметра методу, который затем выполняет что-то в другом потоке, вы, по сути, работаете с копией этого типа значений (примечание Джоша о копировании в режиме on- пишите, несмотря на это). Это обеспечивает целостность объекта, переданного методу. Это нормально (и здесь были достаточно охвачены другие ответы).

Но это осложняется, когда вы имеете дело с закрытием. Рассмотрим, например, следующее:

struct Person { 
    var firstName: String 
    var lastName: String 
} 

var person = Person(firstName: "Rob", lastName: "Ryan") 

DispatchQueue.global().async { 
    Thread.sleep(forTimeInterval: 1) 
    print("1: \(person)") 
} 

person.firstName = "Rachel" 
Thread.sleep(forTimeInterval: 2) 
person.lastName = "Moore" 
print("2: \(person)") 

Очевидно, что вы не были бы вообще sleep, но я делаю это, чтобы проиллюстрировать этот момент: именно, несмотря на то, что мы имеем дело с типом значения и несколько потоков , person вы ссылаетесь в закрытии такой же экземпляр, с которым вы имеете дело в основном потоке (или в любом другом потоке, на котором это выполнялось), а не на его копии. Если вы имеете дело с изменяемым объектом, это не является потокобезопасным.

Я придумал этот пример, чтобы проиллюстрировать этот момент, где в заявлении print в закрытии выше будет сообщаться «Рейчел Райан», фактически показывающий состояние типа значения Person в несогласованном состоянии.

С затворами с использованием типов значений, если вы хотите наслаждаться семантикой значений, вы должны изменить этот async вызов использовать отдельную переменный:

let separatePerson = person 
queue.async { 
    Thread.sleep(forTimeInterval: 1) 
    print("1: \(separatePerson)") 
} 

Или, еще проще, использовать «список захвата», что указывает на то, что переменные типа значения должны быть захвачены закрытия:

queue.async { [person] in 
    Thread.sleep(forTimeInterval: 1) 
    print("1: \(person)") 
} 

с любым из этих примеров, вы теперь пользуются семантику значений, копирование объекта, а print заявление будет правильно сообщить «Роб Райан» даже Тхо ugh оригинал person объект мутируется в другом потоке.

Итак, если вы имеете дело со типами значений и замыканиями, типы значений могут делиться по потокам, если вы явно не используете список захвата (или что-то подобное), чтобы использовать семантику значений (т.копируя объект по мере необходимости).

+1

Когда я впервые прочитал ответы здесь, я подумал, что тип значения NO NO имеет многопоточную проблему. Но это верно, если вы захватили/скопировали. Если вы манипулируете * точным * ** одинаковым значением **, то у вас есть ** проблемы ... – Honey

+0

* Типы значений немного сложнее. Да, как указывали другие, если вы передаете тип значения в качестве параметра методу, который затем делает что-то в другом потоке * <- Не пишете ли вы немного запутанно? Строка не может быть мутирована при передаче другой функции того же потока. Скажем, я передал структуру в func, параметр внутри func неизменен ... – Honey

+0

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

3

Да, ссылки совместно используют, если их используют несколько потоков; вот в чем проблема. Все темы относятся к к тем же фактическим данным в памяти. Затем им требуются механизмы синхронизации, чтобы гарантировать, что чтение и запись отдельных потоков не конфликтуют. Эти механизмы имеют затраты на сложность кода и производительность.

Экземпляры типов значений не разделяются: каждый поток получает свою собственную копию. * Это означает, что каждый поток может читать и записывать в свой экземпляр, не беспокоясь о том, что делают другие потоки.


* Со стандартным исключением копирования при записи для Свифта STDLIB типов: фактическая копия выполняется, только если данные мутируют.

2

Это смехотворно сформулировано.

Типы значений: данные будут использоваться в коде для нескольких потоков.

Таким образом, я считаю, что они полезны, когда вы хотите, чтобы многие потоки читали ваши данные. Это связано с тем, что вы знаете, что всякий раз, когда вы даете новый поток копию ваших данных, вы не подвергаете никакие другие копии риску неожиданной мутации из других потоков.

Использование типов значений в таком контексте, в котором вам не требуется совместное изменчивое состояние, позволяет избежать множества классов ошибок (условия гонки, блокировка блокировки, блокировка в реальном времени и т. Д.), Которые исходят от обращения к ссылочным типам ,

ссылочные типы: Вы хотите создать общедоступное, изменяемое состояние

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

1

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

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

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

0

Типы значений: Данные будут использоваться в коде через несколько потоков.

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

Ссылочные типы: Вы хотите создать общедоступное, изменяемое состояние

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

Смежные вопросы