Выясните, когда происходит переключение контекста в Swift

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

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

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

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

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

2 ответа

Решение

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

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

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

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

00:00.770.247   Virtual memory Zero Fill took 10.50 µs  small_free_list_add_ptr ← (31 other frames) 

Я думаю, это довольно крутой вопрос, но не ясный. Ответ - все о моем понимании вашего вопроса. Обычно, если вы реализуете 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, Это обычное использование переключения контекста.

Другие вопросы по тегам