Ios 在nsrunlop中正确使用辅助NSThread
我有一个性能敏感的代码,用于实时播放视频帧。我在这里做了一些可以并行化的工作,因为这是一个性能敏感的代码,延迟是关键,所以我决定使用Ios 在nsrunlop中正确使用辅助NSThread,ios,objective-c,multithreading,nsthread,nsrunloop,Ios,Objective C,Multithreading,Nsthread,Nsrunloop,我有一个性能敏感的代码,用于实时播放视频帧。我在这里做了一些可以并行化的工作,因为这是一个性能敏感的代码,延迟是关键,所以我决定使用NSThread而不是GCD 我需要的:我需要有NSThread,它将在特定时间段安排一些工作。线程完成其工作后,将进入睡眠状态,直到新的工作到达 不幸的是,关于NSThread在互联网上的正确使用技术,没有太多的信息,所以我根据我设法找到的信息位组装了我的例程 您可以在上面找到整个工作流: 1) 初始化我的NSThread。此代码只按预期启动一次 _myThrea
NSThread
而不是GCD
我需要的:我需要有NSThread
,它将在特定时间段安排一些工作。线程完成其工作后,将进入睡眠状态,直到新的工作到达
不幸的是,关于NSThread
在互联网上的正确使用技术,没有太多的信息,所以我根据我设法找到的信息位组装了我的例程
您可以在上面找到整个工作流:
1) 初始化我的NSThread
。此代码只按预期启动一次
_myThread = [[NSThread alloc] initWithTarget:self selector:@selector(_backgroundMethod) object:nil];
_myThread.threadPriority = 0.8; //max priority is 1.0. Let's try at 0.8 and see how it performs
[_myThread start];
2) \u背景方法
代码:
- (void)_backgroundMethod
{
NSLog(@"Starting the thread...");
[NSTimer scheduledTimerWithTimeInterval:FLT_MAX target:self selector:@selector(doNothing:) userInfo:nil repeats:YES];
BOOL done = false;
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
do {
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
}
- (void)doNothing:(NSTimer *)sender { }
3) 当线程有东西要处理时,我会打下一个电话:
[self performSelector:@selector(_doSomeCalculation) onThread:_myThread withObject:nil waitUntilDone:NO];
哪个调用下一个方法:
- (void) _doSomeCalculation
{
//do some work here
}
所以我的问题是:
1) 当我初始化NSThread时,我传递一个选择器。那个选择器的用途是什么?据我所知,这个选择器的唯一用途是控制线程的RunLoop,我不应该在这里进行任何计算。因此,我正在使用一个无限计时器启动nsrunlop
,以使其保持活动状态,而不必在循环期间不断运行。这是正确的方法吗
2) 如果我可以在我在NSThread
init阶段传递的选择器中进行计算,那么我如何在不使用performSelector
的情况下向nsrunlop发送信号以执行一个循环呢?我想我不应该通过与performSelector
完全相同的方法,因为它会很混乱,对吗
我已经阅读了苹果提供的很多信息,但所有这些几乎都是理论性的,而那些提供的代码示例更让我困惑
如有任何澄清,将不胜感激。提前谢谢
编辑:
还有一个问题-如何计算线程所需的stackSize
?有什么技巧可以做到这一点吗
因为这是一个性能敏感的代码,延迟是关键,所以我决定使用NSThread而不是GCD
你通常不应该这样做,除非你有一个坚实的理解GCD和确切地知道你要放弃什么。正确使用,GCD是高度优化的,并与操作系统紧密集成。手动使用NSThread,然后使用performSelector
在ObjC中运行循环,这尤其令人惊讶。以这种方式调用PerformSelect会引入与GCD串行队列相同的未知延迟。如果线程已经很忙,那么您将对选择器进行排队,就像对块进行排队一样(但您将增加objc\u msgSend
的开销)。GCD并发队列的性能会更好。为了匹配GCD,您需要实现一个适当的线程池(或者至少添加取消)。做得好,对于特定的用例,这可能比GCD更好,但它必须做得很好,这很复杂
如注释所示:
注意:虽然对于线程之间的偶尔通信很好,但对于线程之间的时间关键型或频繁通信,不应使用performSelector:onThread:withObject:waitUntilDone:方法
如果希望线程之间的通信延迟较低,通常需要使用信号量,例如NSConditionLock
,而不是runloop
也就是说,让我们进入实际问题
performSelector:onThread:…
接口通常用于一次性操作。实现长时间运行的专用线程的更常见方法是子类化NSThread
并重写main
。类似这样的东西(这是根据《线程编程指南》中的代码组合而成的,未经测试;我已经在GCD中完成了多年的高性能工作,所以我可能在这里搞错了一些东西)
您将生成一些线程,如:
workers = @[[WorkerThread new], [WorkerThread new]];
for (worker in workers) {
[worker start];
}
[WorkerThread submitWork: data];
for (worker in workers) {
[worker cancel];
}
然后关闭线程,如:
workers = @[[WorkerThread new], [WorkerThread new]];
for (worker in workers) {
[worker start];
}
[WorkerThread submitWork: data];
for (worker in workers) {
[worker cancel];
}
糟糕的决定。使用GCD
。它被设计为“杀死”NSThread
。你需要的东西都有了。你现在只是在重新发明GCD。您可以使用directGCD
或Objective-C的it包装器NSOperationQueue
Hello!以下是Apple在《从线程迁移》一文中对NSThread
的看法-重要的是要记住,队列不是替换线程的灵丹妙药。队列提供的异步编程模型适用于延迟不是问题的情况。尽管队列提供了配置队列中任务的执行优先级的方法,但较高的执行优先级并不能保证在特定时间执行任务。因此,在需要最小延迟的情况下,线程仍然是更合适的选择,例如在音频和视频播放中。
所以我想指出,我决定尝试NSThread
,因为在特定情况下,GCD
存在某些问题,比如延迟随着时间的推移而减少,以及不同设备上的性能不均衡。我需要更多地控制我的任务是如何执行的,并学习如何正确地执行它。我认为苹果在这里的意思是,你在线程中执行简单的顺序工作:从输入中获取数据,处理它,将它放入输出。当您创建运行循环并执行选择器时,没有这种调度机制。执行选择器也比直接函数调用花费更多的时间,如果延迟如此重要,你应该考虑一下。在这一点上,我将不得不使用@Cy-4AH。可以使用GCD在单个队列上完成所有工作,也可以对每个进程使用NSThread
而不使用run循环。看来你不止一个。在这两种情况下,当需要在此线程中执行的工作太多而无法处理时,都会产生延迟。打开的线程数量将增加,或者先前的t