iOS 多线程实现小结

简介

在iOS中,我们需要将非UI且耗时的任务放在主线程当中执行,同时确保在任务完成时进行回调。常用的三种实现多线程方式如下:

1. GCD

2. NSThread

3. NSOperation / NSOperationQueue

先就GCD小结下。

小结分析

下面分别予以简单小结。

一 GCD

GCD 是Grand Central Dispatch的缩写,是苹果提供的基于block回调的多线程实现方式。

GCD维护线程的创建和调度及生命周期,程序员只需负责进行业务逻辑的处理。

GCD有异步和同步执行任务两种处理方式.使用时,无须关心队列和任务的调度,由系统负责安排。相应的API函数定义在dispatch/queue.h当中。

根据该文档中的注释:

Dispatch is an abstract model for expressing concurrency via simple but

powerful API.

*

* At the core, dispatch provides serial FIFO queues to which blocks may be

* submitted. Blocks submitted to these dispatch queues are invoked on a pool

* of threads fully managed by the system. No guarantee is made regarding

* which thread a block will be invoked on; however, it is guaranteed that only

* one block submitted to the FIFO dispatch queue will be invoked at a time.

*

* When multiple queues have blocks to be processed, the system is free to

* allocate additional threads to invoke the blocks concurrently. When the

* queues become empty, these threads are automatically released.


/*!

* @typedef dispatch_queue_t

*

* @abstract

* Dispatch queues invoke blocks submitted to them serially in FIFO order. A

* queue will only invoke one block at a time, but independent queues may each

* invoke their blocks concurrently with respect to each other.

*

* @discussion

* Dispatch queues are lightweight objects to which blocks may be submitted.

* The system manages a pool of threads which process dispatch queues and

* invoke blocks submitted to them.

*

* Conceptually a dispatch queue may have its own thread of execution, and

* interaction between queues is highly asynchronous.

*

* Dispatch queues are reference counted via calls to dispatch_retain() and

* dispatch_release(). Pending blocks submitted to a queue also hold a

* reference to the queue until they have finished. Once all references to a

* queue have been released, the queue will be deallocated by the system.

*/

系统维护一个FIFO(先进先出顺序)的队列,提交到队列中的block任务由系统负责分配线程执行,但不能保证哪个线程会执行,且多个线程中只有一个保证在执行。当系统中线程数不够时,将自动创建线程。block为空时,对应的线程会自动被销毁。

dispatch通过dispatch_retain() 和dispatch_release()来进行引用记数管理。

(一)GCD的调用:

1.异步调用:

1.1 

void dispatch_async(dispatch_queue_tqueue,dispatch_block_tblock);

调用之后,会立即返回,不等待提交的block执行完成。

1.2

void dispatch_async_f(dispatch_queue_tqueue,

void*context,

dispatch_function_twork);

/*!

* @function dispatch_async_f

*

* @abstract

* Submits a function for asynchronous execution on a dispatch queue.

*

* @discussion

* See dispatch_async() for details.

*

* @param queue

* The target dispatch queue to which the function is submitted.

* The system will hold a reference on the target queue until the function

* has returned.

* The result of passing NULL in this parameter is undefined.

*

* @param context

* The application-defined context parameter to pass to the function.

*

* @param work

* The application-defined function to invoke on the target queue. The first

* parameter passed to this function is the context provided to

* dispatch_async_f().

* The result of passing NULL in this parameter is undefined.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORTDISPATCH_NONNULL1DISPATCH_NONNULL3DISPATCH_NOTHROW

void

dispatch_async_f(dispatch_queue_tqueue,

void*context,

dispatch_function_twork);

context可以传0或Nsnull,详见How to use dispatch_async_f

2. 同步调用:

2.1 void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

将block中的任务执行完成后才会返回。通常用于设置和与服务器同步,等待设置完成和服务器返回后才进行下一步操作。

/*!

* @function dispatch_sync

*

* @abstract

* Submits a block for synchronous execution on a dispatch queue.

*

* @discussion

* Submits a block to a dispatch queue like dispatch_async(), however

* dispatch_sync() will not return until the block has finished.

*

* Calls to dispatch_sync() targeting the current queue will result

* in dead-lock. Use of dispatch_sync() is also subject to the same

* multi-party dead-lock problems that may result from the use of a mutex.

* Use of dispatch_async() is preferred.

*

* Unlike dispatch_async(), no retain is performed on the target queue. Because

* calls to this function are synchronous, the dispatch_sync() "borrows" the

* reference of the caller.

*

* As an optimization, dispatch_sync() invokes the block on the current

* thread when possible.

*

* @param queue

* The target dispatch queue to which the block is submitted.

* The result of passing NULL in this parameter is undefined.

*

* @param block

* The block to be invoked on the target dispatch queue.

* The result of passing NULL in this parameter is undefined.

*/

#ifdef __BLOCKS__

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW

void

dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

#endif

2.2 void dispatch_sync_f(dispatch_queue_t queue,

void *context,

dispatch_function_t work);

/*!

* @function dispatch_sync_f

*

* @abstract

* Submits a function for synchronous execution on a dispatch queue.

*

* @discussion

* See dispatch_sync() for details.

*

* @param queue

* The target dispatch queue to which the function is submitted.

* The result of passing NULL in this parameter is undefined.

*

* @param context

* The application-defined context parameter to pass to the function.

*

* @param work

* The application-defined function to invoke on the target queue. The first

* parameter passed to this function is the context provided to

* dispatch_sync_f().

* The result of passing NULL in this parameter is undefined.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NONNULL3 DISPATCH_NOTHROW

void

dispatch_sync_f(dispatch_queue_t queue,

void *context,

dispatch_function_t work);

3. 多次调用

3.1 void dispatch_apply(size_titerations,dispatch_queue_tqueue, void(^block)(size_t));

函数原型如下:

/*!

* @function dispatch_apply

*

* @abstract

* Submits a block to a dispatch queue for multiple invocations.

*

* @discussion

* Submits a block to a dispatch queue for multiple invocations. This function

* waits for the task block to complete before returning. If the target queue

* is concurrent, the block may be invoked concurrently, and it must therefore

* be reentrant safe.

*

* Each invocation of the block will be passed the current index of iteration.

*

* @param iterations

* The number of iterations to perform.

*

* @param queue

* The target dispatch queue to which the block is submitted.

* The result of passing NULL in this parameter is undefined.

*

* @param block

* The block to be invoked the specified number of iterations.

* The result of passing NULL in this parameter is undefined.

*/

#ifdef __BLOCKS__

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORTDISPATCH_NONNULL3DISPATCH_NOTHROW

void

dispatch_apply(size_titerations,dispatch_queue_tqueue,

void(^block)(size_t));

#endif

3.2 void dispatch_apply_f(size_titerations,dispatch_queue_tqueue,

void*context,

void(*work)(void*,size_t));

/*!

* @function dispatch_apply_f

*

* @abstract

* Submits a function to a dispatch queue for multiple invocations.

*

* @discussion

* See dispatch_apply() for details.

*

* @param iterations

* The number of iterations to perform.

*

* @param queue

* The target dispatch queue to which the function is submitted.

* The result of passing NULL in this parameter is undefined.

*

* @param context

* The application-defined context parameter to pass to the function.

*

* @param work

* The application-defined function to invoke on the target queue. The first

* parameter passed to this function is the context provided to

* dispatch_apply_f(). The second parameter passed to this function is the

* current index of iteration.

* The result of passing NULL in this parameter is undefined.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORTDISPATCH_NONNULL4DISPATCH_NOTHROW

void

dispatch_apply_f(size_titerations,dispatch_queue_tqueue,

void*context,

void(*work)(void*,size_t));

(二)GCD的队列

GCD中有3个队列:

2.1 主队列

dispatch_get_main_queue(void)

主队列一般进行UI线程操作,及与用户交互。因此,对于长时间的复杂逻辑处理任务,一般都将放到后台队列当中进行。为了操作流畅和用户体验,网络请求及数据库操作等任务,都不要在主队列当中进行。

/*!

* @function dispatch_get_main_queue

*

* @abstract

* Returns the default queue that is bound to the main thread.

*

* @discussion

* In order to invoke blocks submitted to the main queue, the application must

* call dispatch_main(), NSApplicationMain(), or use a CFRunLoop on the main

* thread.

*

* @result

* Returns the main queue. This queue is created automatically on behalf of

* the main thread before main() is called.

*/

DISPATCH_INLINE DISPATCH_ALWAYS_INLINE DISPATCH_CONST DISPATCH_NOTHROW

dispatch_queue_t

dispatch_get_main_queue(void)

{

return DISPATCH_GLOBAL_OBJECT(dispatch_queue_t, _dispatch_main_q);

}

2.2 串行队列

创建:

dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

/*!

* @function dispatch_queue_create

*

* @abstract

* Creates a new dispatch queue to which blocks may be submitted.

*

* @discussion

* Dispatch queues created with the DISPATCH_QUEUE_SERIAL or a NULL attribute

* invoke blocks serially in FIFO order.

*

* Dispatch queues created with the DISPATCH_QUEUE_CONCURRENT attribute may

* invoke blocks concurrently (similarly to the global concurrent queues, but

* potentially with more overhead), and support barrier blocks submitted with

* the dispatch barrier API, which e.g. enables the implementation of efficient

* reader-writer schemes.

*

* When a dispatch queue is no longer needed, it should be released with

* dispatch_release(). Note that any pending blocks submitted to a queue will

* hold a reference to that queue. Therefore a queue will not be deallocated

* until all pending blocks have finished.

*

* Passing the result of the dispatch_queue_attr_make_with_qos_class() function

* to the attr parameter of this function allows a quality of service class and

* relative priority to be specified for the newly created queue.

* The quality of service class so specified takes precedence over the quality

* of service class of the newly created dispatch queue's target queue (if any)

* as long that does not result in a lower QOS class and relative priority.

*

* When no quality of service class is specified, the target queue of a newly

* created dispatch queue is the default priority global concurrent queue.

*

* @param label

* A string label to attach to the queue.

* This parameter is optional and may be NULL.

*

* @param attr

* DISPATCH_QUEUE_SERIAL, DISPATCH_QUEUE_CONCURRENT, or the result of a call to

* the function dispatch_queue_attr_make_with_qos_class().

*

* @result

* The newly created dispatch queue.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT

DISPATCH_NOTHROW

dispatch_queue_t

dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

获取指定label的队列:

const char *dispatch_queue_get_label(dispatch_queue_t queue);

/*!

* @function dispatch_queue_get_label

*

* @abstract

* Returns the label of the given queue, as specified when the queue was

* created, or the empty string if a NULL label was specified.

*

* Passing DISPATCH_CURRENT_QUEUE_LABEL will return the label of the current

* queue.

*

* @param queue

* The queue to query, or DISPATCH_CURRENT_QUEUE_LABEL.

*

* @result

* The label of the queue.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_PURE DISPATCH_WARN_RESULT DISPATCH_NOTHROW

const char *

dispatch_queue_get_label(dispatch_queue_t queue);

2.3 全局队列

dispatch_get_global_queue(long identifier, unsigned long flags);

identifier表示优先级:有四个值:

DISPATCH_QUEUE_PRIORITY_HIGH:        高优先级,一般是需要处理的紧急任务或UI线程

 DISPATCH_QUEUE_PRIORITY_DEFAULT:      默认优先级

DISPATCH_QUEUE_PRIORITY_LOW:          低优先级

 DISPATCH_QUEUE_PRIORITY_BACKGROUND:后台进程,比如网络或数据库请求

flags为保留值,一般设为0.

/*!

* @function dispatch_get_global_queue

*

* @abstract

* Returns a well-known global concurrent queue of a given quality of service

* class.

*

* @discussion

* The well-known global concurrent queues may not be modified. Calls to

* dispatch_suspend(), dispatch_resume(), dispatch_set_context(), etc., will

* have no effect when used with queues returned by this function.

*

* @param identifier

* A quality of service class defined in qos_class_t or a priority defined in

* dispatch_queue_priority_t.

*

* It is recommended to use quality of service class values to identify the

* well-known global concurrent queues:

*  - QOS_CLASS_USER_INTERACTIVE

*  - QOS_CLASS_USER_INITIATED

*  - QOS_CLASS_DEFAULT

*  - QOS_CLASS_UTILITY

*  - QOS_CLASS_BACKGROUND

*

* The global concurrent queues may still be identified by their priority,

* which map to the following QOS classes:

*  - DISPATCH_QUEUE_PRIORITY_HIGH:        QOS_CLASS_USER_INITIATED

*  - DISPATCH_QUEUE_PRIORITY_DEFAULT:      QOS_CLASS_DEFAULT

*  - DISPATCH_QUEUE_PRIORITY_LOW:          QOS_CLASS_UTILITY

*  - DISPATCH_QUEUE_PRIORITY_BACKGROUND:  QOS_CLASS_BACKGROUND

*

* @param flags

* Reserved for future use. Passing any value other than zero may result in

* a NULL return value.

*

* @result

* Returns the requested global queue or NULL if the requested global queue

* does not exist.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_CONST DISPATCH_WARN_RESULT DISPATCH_NOTHROW

dispatch_queue_t

dispatch_get_global_queue(long identifier, unsigned long flags);

另外,调试和打日志时,需要用到

dispatch_queue_t dispatch_get_current_queue(void);

函数得到当前队列。

线程延时执行:可以使用

void dispatch_after(dispatch_time_t when,

dispatch_queue_t queue,

dispatch_block_t block);

/*!

* @function dispatch_after

*

* @abstract

* Schedule a block for execution on a given queue at a specified time.

*

* @discussion

* Passing DISPATCH_TIME_NOW as the "when" parameter is supported, but not as

* optimal as calling dispatch_async() instead. Passing DISPATCH_TIME_FOREVER

* is undefined.

*

* @param when

* A temporal milestone returned by dispatch_time() or dispatch_walltime().

*

* @param queue

* A queue to which the given block will be submitted at the specified time.

* The result of passing NULL in this parameter is undefined.

*

* @param block

* The block of code to execute.

* The result of passing NULL in this parameter is undefined.

*/

#ifdef __BLOCKS__

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_NONNULL2 DISPATCH_NONNULL3 DISPATCH_NOTHROW

void

dispatch_after(dispatch_time_t when,

dispatch_queue_t queue,

dispatch_block_t block);

#endif


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • ‌书法是我国古代人民智慧的结晶,自小看到会写毛笔字的人对他们都特别的敬仰羡慕,这是一种特别神圣的艺术,以至于小时候...
    形影々相依阅读 647评论 0 1
  • 静静的第二堂主题美术课作品,Merry Christmas!
    谭潭潭阅读 145评论 0 0
  • 今天回学校了,一回到教室就开始我的手工DIY ,今天做的是小猫咪,做好的第一个送给了我的大脸师傅,是不是很可爱呢 ...
    清风微寒阅读 171评论 1 2
  • 大学里我学的是生物,而现在从事的工作是网络推广,目前正在学习SEO,长远目标是精通推广,包括线上及线下。当初选专业...
    淘米日记本阅读 497评论 0 1
  • 功夫和认知 在传统武术的领域,存在的各种对功夫的看法和认知,争论一直不停,但一直没有一种判断和停止争论的权威的判定...
    a9ac3e50d244阅读 444评论 0 0