找出 Swift 中上下文切换的时间

Figure out when a context switch is happening in Swift

老实说,我不知道我的问题是否有解决方案,但我想在 Swift 中捕捉上下文切换的时间。

我正在想象一个需要很长时间才能完成的功能,例如远程服务器上的写操作,我在想是否有办法了解线程何时(至少在哪一行)正在执行该任务的那个正在执行上下文切换,因为必须执行另一个等待很长时间的任务。

抱歉,如果您的问题看起来很愚蠢,或者我在尝试解释上述内容时犯了错误

编辑:

我说的是调度程序自动请求的上下文切换。再想象一下,我们正处于这个执行大量操作的长函数的中间,调度程序给了这个任务几秒钟的时间,例如 10 秒以使其完成。如果进程用完时间并且没有结束任务,它将被挂起,例如线程将执行另一个进程的另一个任务。当它结束时,调度程序可能会考虑再次尝试暂停的作业,并且将从暂停的地方开始恢复执行(因此将从 PC 寄存器读取值并继续执行)

我认为这是一个很酷的问题,但 clear.The 答案完全是关于我对你的问题的理解。通常,如果您实现 C++ 或 C 程序进行上下文切换,请考虑使用互斥锁或 semaphores.In 编写代码,这些部分进程或线程在临界区工作,有时会手动或中断方式执行上下文切换。在 iOS 中有相同的并发实现,例如 DispatchSemaphore。(实际上互斥量是一个与锁系统一起工作的信号量。)您可以阅读 here 的文档。

为此,这是 Semaphore class 在 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 实现它时,您可能会在 DispatchQueue.main.async 中调用 reloadData 方法。这是上下文切换的常见用法。

您绝对可以得到您所要求的,但我有一种感觉,它对您的用处远没有您想象的那么大。绝大多数(大量,大量!)上下文切换将发生在您可能认为的点 "uninteresting." lstat64()mach_vm_map_trap()mach_msg_trap()mach_port_insert_member_trap(), kevent_id(), 列表还在继续。大多数线程大部分时间都花在 OS 堆栈的深处。 "A write operation on a remote server" 在花费很长时间后不会阻塞。它会主动阻止自己,因为它知道这将花费(令人难以置信的)很长一段时间。

即便如此,您当然可以使用 Instruments 进行探索。只需选择 System Trace 配置文件,它就会向您显示所有线程和系统核心,以及您的线程和设备上所有其他线程的调度方式、每个系统调用等等。信息量巨大,所以你通常一次只分析几秒钟。但它看起来像这样:

如果您正处于上下文切换成为主要瓶颈的地步,这将是有用的信息。如果您正在处理过度的锁争用,或者如果您因为不断被其他线程打断而使您的 L1 高速缓存崩溃,则可能会发生这种情况。因此,如果您有一些线程希望保持 运行 相当连续,并且它被阻止了,这就是非常有价值的信息。或者,如果您有两个您认为应该顺畅地来回工作的线程,但它们似乎在打架(快速切换),那么这就是您可以处理的问题。 (但这很少是您首先要寻找性能调优的地方之一,除非您正在处理相当低级的代码。)

根据您的描述,我认为您可能对调度程序有错误的认识。调度程序中的任何内容都不会达到 10 秒的数量级。在调度程序世界中,毫秒是很多时间。您应该考虑需要微秒甚至纳秒的事情。如果您正在编写假定从 RAM 中获取数据是免费的代码,那么您的时间尺度是错误的。 A network call is so ludicrously slow that you can basically estimate it as "forever." 在上下文切换级别,您正在查看以下事件:

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