在iOS上管理CPU密集型线程 [英] Managing CPU intensive threads on iOS

查看:103
本文介绍了在iOS上管理CPU密集型线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一位经验丰富的C / C ++程序员,正在加速iPhone上的Objective C。我做了很多搜索,但没有找到一个令人满意的答案,一定是一个常见的问题;我很抱歉,如果在其他地方得到解答,指针将不胜感激。



我的应用程序非常耗费CPU。 UI具有显示进度的简单显示和开始/停止按钮。分配最多CPU周期以完成工作的最佳方法是什么,同时仍然确保显示器定期更新并且启动/停止按钮响应?我已经读过你不应该在主线程中工作,但除此之外我还没有找到很多建议。鉴于此,我已经在NSOperation队列中实现了我的工作。我还将屏幕刷新放在自己的队列中。我还用NSThread sleepForTimeIntervals自由地散布了代码。我已经尝试了从.001到1的不同睡眠时间(例如[NSThread sleepForTimeIntervals .1])。尽管如此,屏幕显示最多是缓慢(10秒)并按下停止按钮突出显示按钮但是没有任何事情再次发生10秒。



1。)NSOperation队列是否合理?如果没有,还有什么?
2.)如何最大限度地减少睡眠? (显然我希望工作能够获得尽可能多的周期/合理,并且我不确定我的睡眠是否对所有要更新的UI都做了任何事情。)
3.)是否有更好的技术保持UI最新?例如,我可以使用NSTimer或其他方法向UI发送消息,告诉它更新和/或检查按钮的状态吗?



谢谢你你的支持。

解决方案


1。)NSOperation队列是否合理?如果没有,还有什么?


NSOperationQueue听起来很合理。



<当然,您可以选择:pthreads,libdispatch(又名GCD),构建在pthreads之上的c ++线程库等等,如果你没有产生很多/很多,那么它只是归结为模型你喜欢。


2。)如何最小化睡眠? (显然我希望工作能够获得尽可能多的周期/合理,并且我不确定我的睡眠对所有要更新的UI都做了任何事情。)


不要睡觉=)您可以为您的ui元素使用计时器,或者使用显式回调或通知来通知依赖项。如果依赖关系执行ui更新,那么您可能会将消息添加到主线程的消息队列。


3.。有没有更好的保持UI最新的技术?例如,我可以使用NSTimer或其他方法向UI发送消息,告知它更新和/或检查按钮的状态吗?


这真的取决于你在做什么。如果您只想更新进度条,则可以从辅助线程写入值并从主线程中读取值。然后在主运行循环上使用计时器定期向对象发送消息以更新其显示(基于当前值)。对于类似未分级进度指示器的事情,这可能是好的。



另一种替代方案对事件或阶段更有用:它将涉及发布更新(例如通知或回调给代表)从次要线程进行进展(#2下的更多信息)。



更新


我不确定这在iOS模型中是否合适,但听起来确实如此。


是的,没关系 - 你可以采取许多方法。这是'最好'取决于上下文。


我目前的理解是在一个线程(不是主要的!)中启动UI,


你真的没有明确启动UI;通常通过将事件和消息推送到主线程来驱动主线程。主线程使用运行循环并在运行循环的每次迭代中处理排队的消息/事件。您也可以在将来安排这些消息(稍后会详细介绍)。话虽如此,你对UIKit和AppKit(如果你的目标是osx)对象的所有消息都应该在主线程上(作为一种概括,你最终会知道它有例外)。如果你有一个特定的实现,它与消息传递UIKit对象的方法完全分开,并且该程序是线程安全的,那么你可以从任何线程实际执行这些消息,因为它不会影响UIKit实现的状态。最简单的例子:

  @interface MONView:UIView 
@end

@implementation MONView
// ... ...
- (NSString *)iconImageName {return @tortoise.png; } // pure和threadsafe
@end




启动我的工作线程,使用计时器为UI生成信号,以查看进度值并适当更新进度条。出于这个特定应用的目的,你的倒数第二段是充足的,我不需要去最后一段的长度(至少现在)。谢谢。


要做到这一点,你可以使用类似这样的方法:

  @interface MONView:UIView 
{
NSTimer * timer;
MONAsyncWorker * worker; //<<如果您使用NSOperation,这将是您的NSOperation子类。
}

@end

@implementation MONView

//操作'worker'在完成或取消时的回调。
- (void)workerWillExit
{
assert([NSThread isMainThread]); //呼叫主

//结束重复更新
[self.timer invalidate];
self.timer = nil;

//抓住工人需要的东西
self.worker = nil;
//更新ui
}

//计时器回调
- (void)timerUpdateCallback
{
assert([NSThread isMainThread]) ; //调用main
assert(self.worker);

double progress = self.worker.progress;

[self updateProgressBar:progress];
}

//用于启动操作的控制器条目
- (void)beginDownload:(NSURL *)url
{
assert([NSThread isMainThread ]); //调用main
assert(nil == worker); //在视图的生命周期中只调用一次

//创建worker
worker = [[MONAsyncWorker alloc] initWithURL:url];
[self.operationQueue addOperation:worker];

//配置计时器
const NSTimeInterval displayUpdateFrequencyInSeconds = 0.200;
timer = [[NSTimer scheduledTimerWithTimeInterval:displayUpdateFrequencyInSeconds target:self selector:@selector(timerUpdateCallback)userInfo:nil repeats:YES] retain];
}

@end

请注意,这是一个非常原始示范。将计时器,更新处理和操作放在视图的控制器中,而不是视图中也更常见。


I’m an experienced C/C++ programmer coming up to speed on Objective C on the iPhone. I have done a lot of searching, but haven’t found a satisfactory answer on what must be a common question; I apologize if this is answered elsewhere, pointers would be appreciated.

My app is very CPU intensive. The UI has a simple display that shows progress and a start/stop button. What is the best way to allocate the most possible CPU cycles to getting the work done, while still ensuring that the display is updated regularly and the start/stop button is responsive? I have read that you should not do work in the main thread, but beyond that I haven’t found many suggestions. In light of this I have implemented my work in an NSOperation queue. I have also put the screen refresh in its own queue. I have also liberally sprinkled the code with NSThread sleepForTimeIntervals. I have experimented with different sleep times from .001 to 1 ([NSThread sleepForTimeIntervals .1] for instance). In spite of this the screen display is sluggish at best (10s of seconds) and pressing the stop button highlights the button but nothing happens again for 10s of seconds.

1.) Are NSOperation Queues a reasonable choice? If not, what else? 2.) How do I minimize the sleeping? (Obviously I want the work to get as many cycles as possible/reasonable, and I’m not sure that my sleeps are doing anything at all to all the UI to update.) 3.) Is there a better technique to keep the UI up to date? For instance, can I use NSTimer or some other method to send a message to the UI telling it to update and/or check the status of the buttons?

Thank you for your support.

解决方案

1.) Are NSOperation Queues a reasonable choice? If not, what else?

NSOperationQueue sounds like it would be reasonable.

of course, you have choice: pthreads, libdispatch (aka GCD), c++ thread libraries built on top of pthreads, etc, etc , etc. if you don't spawn much/many, then it just comes down to the model you favor.

2.) How do I minimize the sleeping? (Obviously I want the work to get as many cycles as possible/reasonable, and I’m not sure that my sleeps are doing anything at all to all the UI to update.)

don't sleep =) you can use a timer for your ui elements or an explicit callback or notification to notify dependencies. if the dependencies peform ui updates, then you will likely add the message to the main thread's message queue.

3.) Is there a better technique to keep the UI up to date? For instance, can I use NSTimer or some other method to send a message to the UI telling it to update and/or check the status of the buttons?

that really depends on what you are doing. if you merely want to update a progress bar, then you can write the value from the secondary thread and read the value from the main thread. then use a timer on the main run loop to periodically message your object to update its display (based on the current value). for something like an unstaged progress indicator this may be good.

another alternative is more useful for events or stages: it would involve posting updates (e.g. notifications or callbacks to a delegate) from the secondary thread as progress is made (more info under #2).

Update

I wasn't sure this was appropriate in the iOS model, but it sounds like it is.

yes, that's fine - there are many appraches you can take. which is 'best' depends on the context.

My current understanding is to launch the UI in one thread (not the main!),

you really don't explicitly launch the UI; the main thread is (generally) driven by pushing events and messages onto the main thread. the main thread uses a run loop and processes the queued messages/events at each iteration of the run loop. you can also schedule these messages in the future (more on that in a bit). having said that, all your messages to UIKit and AppKit (if you target osx) objects should be on the main thread (as a generalization which you will eventually learn there are exceptions to this). if you have a specific implementation which is completely separated from messaging UIKit objects' methods and that program is thread safe, then you can actually perform those messages from any thread because it does not affect the state of the UIKit implementation. simplest example:

@interface MONView : UIView
@end

@implementation MONView
// ...
- (NSString *)iconImageName { return @"tortoise.png"; } // pure and threadsafe
@end

launch my worker thread, use a timer to generate a signal to the UI to take a look at a progress value and update the progress bar appropriately. For the purposes of this particular application your second to last paragraph is ample and I don't need to go to the lengths of the last paragraph (at least for now). Thank you.

to do this, you can use an approach similar to this:

@interface MONView : UIView
{
    NSTimer * timer;
    MONAsyncWorker * worker; // << this would be your NSOperation subclass, if you use NSOperation.
}

@end

@implementation MONView

// callback for the operation 'worker' when it completes or is cancelled.
- (void)workerWillExit
{
    assert([NSThread isMainThread]); // call on main

    // end recurring updates
    [self.timer invalidate];
    self.timer = nil;

    // grab what we need from the worker
    self.worker = nil;
    // update ui
}

// timer callback
- (void)timerUpdateCallback
{
    assert([NSThread isMainThread]); // call on main
    assert(self.worker);

    double progress = self.worker.progress;

    [self updateProgressBar:progress];
}

// controller entry to initiate an operation
- (void)beginDownload:(NSURL *)url
{
    assert([NSThread isMainThread]); // call on main
    assert(nil == worker); // call only once in view's lifetime

    // create worker
    worker = [[MONAsyncWorker alloc] initWithURL:url];
    [self.operationQueue addOperation:worker];

    // configure timer
    const NSTimeInterval displayUpdateFrequencyInSeconds = 0.200;
    timer = [[NSTimer scheduledTimerWithTimeInterval:displayUpdateFrequencyInSeconds target:self selector:@selector(timerUpdateCallback) userInfo:nil repeats:YES] retain];
}

@end

note that this is a very primitive demonstration. it's also more common to put the timer, update handling, and operation in the view's controller, not the view.

这篇关于在iOS上管理CPU密集型线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆