Use GCD thread groups and GCD semaphores to convert asynchronous threads into synchronous threads.

Source: Internet
Author: User

Use GCD thread groups and GCD semaphores to convert asynchronous threads into synchronous threads.

Sometimes we encounter a situation like this:

At the same time, the data of two network requests is obtained, but the network requests are asynchronous. We need to obtain the data of the two network requests before proceeding to the next operation. At this time, it is the application of thread groups and semaphores.

1 # import "ViewController. h "2 # import <AFNetworking. h> 3 4 5 @ interface ViewController () 6 7 @ end 8 9 @ implementation ViewController10 11-(void) viewDidLoad {12 [super viewDidLoad]; 13 [self getNetworkingData]; 14} 15 16-(void) getNetworkingData {17 NSString * appIdKey = @ "8781e4ef1c73ff20a180d3d7a42a8c04"; 18 NSString * urlString_1 = @ "http://api.openweathermap.org/data/2.5/weather"; 19 NSString * url String_2 = @ "http://api.openweathermap.org/data/2.5/forecast/daily"; 20 NSDictionary * dictionary ={ {@ "lat": @ "40.04991291", 21 @ "lon": @ "116.25626162 ", 22 @ "APPID": appIdKey}; 23 // create group 24 dispatch_group_t group = dispatch_group_create (); 25 // Add the first network request task to the group 26 dispatch_group_async (group, dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ {27 // create the semaphore 28 dispatch_semaphore_t semaphore = disp Atch_semaphore_create (0); 29 // start the network request task 30 AFHTTPSessionManager * manager = [AFHTTPSessionManager manager]; 31 [manager GET: urlString_132 parameters: dictionary33 progress: nil34 success: ^ (NSURLSessionDataTask * _ Nonnull task, id _ Nullable responseObject) {35 NSLog (@ "successful request data 1: % @", [responseObject class]); 36 // if the request is successful, send the semaphores 37 dispatch_semaphore_signal (semaphore); 38} failure: ^ (NSURLSessionDataTask * _ Null Able task, NSError * _ Nonnull error) {39 NSLog (@ "failed request data"); 40 // if the request fails, the semaphore 41 dispatch_semaphore_signal (semaphore) is also sent ); 42}]; 43 // before the network request task is successful, the semaphore waits for 44 dispatch_semaphore_wait (semaphore, DISPATCH_TIME_FOREVER); 45 }); 46 // Add the second network request task to the group 47 dispatch_group_async (group, assign (success, 0), ^ {48 // create the semaphore 49 dispatch_semaphore_t semaphore = dispatch_semaphore_cre Ate (0); 50 // start the network request Task 51 AFHTTPSessionManager * manager = [AFHTTPSessionManager]; 52 [manager GET: urlString_253 parameters: dictionary54 progress: nil55 success: ^ (NSURLSessionDataTask * _ Nonnull task, id _ Nullable responseObject) {56 NSLog (@ "successful request data 2: % @", [responseObject class]); 57 // if the request is successful, send the semaphore 58 dispatch_semaphore_signal (semaphore); 59} failure: ^ (NSURLSessionDataTask * _ Nullable task, NSError * _ Nonnull error) {60 NSLog (@ "failed request data"); 61 // if the request fails, the semaphore 62 dispatch_semaphore_signal (semaphore); 63}] is also sent. 64 // before the network request task is successful, the semaphore waits for 65 bytes (semaphore, DISPATCH_TIME_FOREVER); 66}); 67 dispatch_group_notify (group, dispatch_get_global_queue (queue, 0 ), ^ {68 NSLog (@ "completed the network request, no matter whether the network request fails or succeeded. "); 69}); 70} 71 72 @ end

Print result:

04:01:53. 279 NetWorking [83611: 1508240] successful request data 1 :__ NSCFDictionary
04:01:53. 280 NetWorking [83611: 1508240] successful request data 2 :__ NSCFDictionary
04:01:53. 281 NetWorking [83611: 1508287] completed the network request, regardless of whether the network request failed or succeeded.

In order to compare with the above, I specifically removed all the semaphore code, but kept the use of The GCD thread group, and then run it to view the print results.

1 # import "ViewController. h "2 # import <AFNetworking. h> 3 4 5 @ interface ViewController () 6 7 @ end 8 9 @ implementation ViewController10 11-(void) viewDidLoad {12 [super viewDidLoad]; 13 [self getNetworkingData]; 14} 15 16-(void) getNetworkingData {17 NSString * appIdKey = @ "8781e4ef1c73ff20a180d3d7a42a8c04"; 18 NSString * urlString_1 = @ "http://api.openweathermap.org/data/2.5/weather"; 19 NSString * url String_2 = @ "http://api.openweathermap.org/data/2.5/forecast/daily"; 20 NSDictionary * dictionary ={ {@ "lat": @ "40.04991291", 21 @ "lon": @ "116.25626162 ", 22 @ "APPID": appIdKey}; 23 // create group 24 dispatch_group_t group = dispatch_group_create (); 25 // Add the first network request task to the group 26 dispatch_group_async (group, dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ {27 // start the network request Task 28 AFHTTPSessionManager * manager = [FHTTPSessionManager manager]; 29 [manager GET: urlString_130 parameters: dictionary31 progress: nil32 success: ^ (NSURLSessionDataTask * _ Nonnull task, id _ Nullable responseObject) {33 NSLog (@ "successful request data 1: % @", [responseObject class]); 34} failure: ^ (NSURLSessionDataTask * _ Nullable task, NSError * _ Nonnull error) {35 NSLog (@ "failed request data"); 36}]; 37}); 38 // Add the second network request task to the group 39 dispatch_group_async (group, dispatch_get _ Global_queue (queue, 0), ^ {40 // start the network request Task 41 AFHTTPSessionManager * manager = [AFHTTPSessionManager manager]; 42 [manager GET: urlString_243 parameters: dictionary44 progress: nil45 success: ^ (NSURLSessionDataTask * _ Nonnull task, id _ Nullable responseObject) {46 NSLog (@ "successful request data 2: % @", [responseObject class]); 47} failure: ^ (NSURLSessionDataTask * _ Nullable task, NSError * _ Nonnull Error) {48 NSLog (@ "failed request data"); 49}]; 50}); 51 dispatch_group_y y (group, dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^ {52 NSLog (@ "completed the network request, no matter whether the network request fails or succeeded. "); 53}); 54} 55 56 @ end

Print result:

04:05:09. 378 NetWorking [83698: 1510242] completed the network request, regardless of whether the network request failed or succeeded.
04:05:10. 185 NetWorking [83698: 1510096] successful request data 1 :__ NSCFDictionary
04:05:10. 186 NetWorking [83698: 1510096] successful request data 2 :__ NSCFDictionary

When we see the printed result, we can hardly understand it. Isn't the notify thread group useless? Will asynchronous y be executed only after the asynchronous tasks in the group are completed? What is the situation?

The following code adds lines 33rd, 38, 39, 49, 54, and 55 based on the above Code. Then let's take a look at the printed result:

1 # import "ViewController. h "2 # import <AFNetworking. h> 3 4 5 @ interface ViewController () 6 7 @ end 8 9 @ implementation ViewController10 11-(void) viewDidLoad {12 [super viewDidLoad]; 13 [self getNetworkingData]; 14} 15 16-(void) getNetworkingData {17 NSString * appIdKey = @ "8781e4ef1c73ff20a180d3d7a42a8c04"; 18 NSString * urlString_1 = @ "http://api.openweathermap.org/data/2.5/weather"; 19 NSString * url String_2 = @ "http://api.openweathermap.org/data/2.5/forecast/daily"; 20 NSDictionary * dictionary ={ {@ "lat": @ "40.04991291", 21 @ "lon": @ "116.25626162 ", 22 @ "APPID": appIdKey}; 23 // create group 24 dispatch_group_t group = dispatch_group_create (); 25 // Add the first network request task to the group 26 dispatch_group_async (group, dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ {27 // start the network request Task 28 AFHTTPSessionManager * manager = [FHTTPSessionManager manager]; 29 [manager GET: urlString_130 parameters: dictionary31 progress: nil32 success: ^ (NSURLSessionDataTask * _ Nonnull task, id _ Nullable responseObject) {33 NSLog (@ "% @", [NSThread currentThread]); 34 NSLog (@ "successful request data 1: % @", [responseObject class]); 35} failure: ^ (NSURLSessionDataTask * _ Nullable task, NSError * _ Nonnull error) {36 NSLog (@ "failed request data"); 37}]; 38 NSLog (@ "% @", [NSThread curr EntThread]); 39 NSLog (@ "AFN network request framework request completed"); 40}); 41 // Add the second network request task to the group 42 dispatch_group_async (group, starting (failed, 0), ^ {43 // start the network request Task 44 AFHTTPSessionManager * manager = [AFHTTPSessionManager manager]; 45 [manager GET: urlString_246 parameters: dictionary47 progress: nil48 success: ^ (NSURLSessionDataTask * _ Nonnull task, id _ Nullable responseObject) {49 NSLog (@" % @ ", [NSThread currentThread]); 50 NSLog (@" successful request data 2: % @ ", [responseObject class]); 51} failure: ^ (NSURLSessionDataTask * _ Nullable task, NSError * _ Nonnull error) {52 NSLog (@ "failed request data"); 53}]; 54 NSLog (@ "% @", [NSThread currentThread]); 55 NSLog (@ "AFN network request framework completed"); 56}); 57 dispatch_group_notify (group, dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^ {58 NSLog (@ "completed the network request, no matter whether the network request fails or succeeded. "); 59}); 60} 61 62 @ end

Print the result (Note: The request data may fail, because the url of the network request is a foreign server, but it doesn't matter. Do not care about the details. The print order is the same ):

04:30:07. 406 NetWorking [84306: 1523047] <NSThread: 0x7fc258725e10> {number = 2, name = (null )}
04:30:07. 406 NetWorking [84306: 1523048] <NSThread: 0x7fc258406100> {number = 3, name = (null )}
04:30:07. 407 NetWorking [84306: 1523047] AFN network request framework request completed
04:30:07. 407 NetWorking [84306: 1523048] AFN network request framework request completed
04:30:07. 407 NetWorking [84306: 1523075] completed the network request, regardless of whether the network request failed or succeeded.
04:30:08. 239 NetWorking [84306: 1523016] <NSThread: 0x7fc258507af0> {number = 1, name = main}
04:30:08. 239 NetWorking [84306: 1523016] successful request data 1 :__ NSCFDictionary
04:30:08. 240 NetWorking [84306: 1523016] <NSThread: 0x7fc258507af0> {number = 1, name = main}
04:30:08. 240 NetWorking [84306: 1523016] successful request data 2 :__ NSCFDictionary

 

Summary: It is time-consuming to process network requests and response data. It is also a common situation in our development, the process of performing other operations after the network request and response data processing are also common in our development. According to the order in which the third part of the code (without the semaphore code) prints the result, we can know that the network request task is submitted to the subthread for asynchronous processing, A network request is a task and a network response is a task. Do not confuse these two processes. The data that receives the network response and processes the returned response is not executed in the Child thread. We use the block (such as 48 ~ There are two blocks between the 53 rows.) print the current thread and you will find that the block for callback Response Processing is executed in the main thread.

If the reader is familiar with the communication mechanism of block callback, it is not difficult to understand that the block in the callback response is actually called and executed by the underlying code of the AFN framework, this part of the code is obviously executed in the main thread.

 

At this time, if we need to confirm that the data in the main thread that receives the network response is processed before the final operation is executed, it seems that relying solely on the thread group is not enough, so the rarely used GCD semaphores will be useful.

Of course, if the above Code does not use a GCD thread group and only uses the GCD semaphores for processing, you can leave this for your own exploration.

 

Finally, let's make a summary: the precondition for using a semaphore is to find out which thread you want to process, which thread to continue executing, and then use the semaphore.

For example, in the above AFN network request example, the block callback is executed in the main thread, while the get request is executed in the self-created asynchronous subthread. As required, you need to create an asynchronous subthread and wait until the block in the main thread is executed. Therefore, the asynchronous subthread requires a semaphore wait, and the main thread sets a signal sending semaphore.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.