Выясните, когда происходит переключение контекста в Swift - PullRequest
0 голосов
/ 13 декабря 2018

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

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

Извините, если вам может показаться глупым вопрос или я допустил ошибки, пытаясь объяснить вышеприведенное

РЕДАКТИРОВАТЬ:

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

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

Вы можете абсолютно точно получить то, о чем просили, но я чувствую, что это будет гораздо менее полезно для вас, чем вы можете поверить.Подавляющее (огромное, огромное!) Большинство переключений контекста происходит в моменты, которые вы, вероятно, считаете «неинтересными».lstat64(), mach_vm_map_trap(), mach_msg_trap(), mach_port_insert_member_trap(), kevent_id(), список можно продолжить.Большинство потоков проводят большую часть своего времени в стеке ОС.«Операция записи на удаленном сервере» не будет блокироваться после того, как она займет много времени.Он будет активно блокировать себя, потому что знает, что это займет (ошеломительно) длительный период времени.

Несмотря на это, вы, безусловно, можете исследовать это с помощью инструментов.Просто выберите профиль System Trace, и он покажет вам все потоки и системные ядра, и как ваши потоки и все другие потоки на устройстве планируются, каждый системный вызов и т. Д. И т. Д. И т. Д. Это огромный объем информации,Таким образом, вы обычно только профиль на несколько секунд за один раз.Но это будет выглядеть примерно так:

Instruments with System Trace

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

Из вашего описания, я думаю, вы можете иметь неверное представление опланировщик.Ничего в планировщике не будет порядка 10 секунд.В мире планировщика миллисекунды - это много времени.Вы должны думать о вещах, которые занимают микросекунды и даже наносекунды.Если вы работаете над кодом, предполагающим, что выборка данных из ОЗУ бесплатна, значит, вы выбрали неправильный временной масштаб. Сетевой вызов настолько смехотворно медленный, что его можно оценить как «навсегда». На уровне переключения контекста вы смотрите на такие события, как:

00:00.770.247   Virtual memory Zero Fill took 10.50 µs  small_free_list_add_ptr ← (31 other frames) 
0 голосов
/ 13 декабря 2018

Я думаю, это довольно крутой вопрос, но не ясный. Ответ - все о моем понимании вашего вопроса.Обычно, если вы реализуете C ++ или C программу для переключения контекста, подумайте, что вы пишете код с мьютексами или семафорами. В этих разделах процессы или потоки работают в критической секции, а иногда и там, где переключение контекста выполняется вручную или способом прерывания.В iOS есть такая же идентичная реализация для параллелизма, такая как DispatchSemaphore. (На самом деле mutex - это семафор, работающий с системой блокировки.) Вы можете прочитать документацию по здесь .

Для начала, это определение класса Semaphore в Swift.

class DispatchSemaphore : DispatchObject

Вы можете инициировать его с помощью значения типа int, например

let semaphore = DispatchSemaphore(value: intValue)

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

 var lock = Lock()

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

Очевидно, это похоже на POSIX pthread_lock_t

Вы можете обрабатывать переключение контекста в критической секции блокировки или семафора следующим образом:

lock.lock()
// critical section
// handle the calculation, if its longer unlock, or let it do its job
lock.unlock()


semaphore.wait(timeout: DispatchTime.distantFuture)
// critical section
// handle the calculation, if its too long signal to exit it in here, or let it do its job
// if it is a normal job, it will be signal for exit already.
semaphore.signal()

Обработанный ответ содержит переключение контекста в потоках.

Дополнение к моему вопросуКогда вы спрашиваете о переключении контекста, его естественным средством является изменение потоков или процессов в основномПоэтому, когда вы получаете данные из фонового потока и затем реализуете их для UITableView, вы, вероятно, выполните вызов метода reloadData в DispatchQueue.main.async.Это обычное использование переключения контекста.

...