美文网首页
iOS 多线程实现小结

iOS 多线程实现小结

作者: adduct | 来源:发表于2017-03-23 00:32 被阅读0次

    简介

    在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


    相关文章

      网友评论

          本文标题:iOS 多线程实现小结

          本文链接:https://www.haomeiwen.com/subject/vqeanttx.html