苹果多线程怎么开 王者荣耀ios多线程程开启教程分享

在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
for (int i = 0; i & 3 ; i++) {
dispatch_queue_t queue = dispatch_queue_create(&#const char *label#&, &#dispatch_queue_attr_t attr#&)
dispatch_async(queue, ^{
BSLog(@"当前线程为 : %@", [NSThread currentThread]);
类似以上的代码,queue我不晓得该怎么写了,求教,万分感谢
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
看来你是把队列和线程的概念弄混淆了。。。队列的串行还是并行,决定了里面的block是怎样被执行的多个队列不一定对应多个线程
同步到新浪微博
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。相关文章链接:
......待续
在多线程简介中,我已经说明过了,为了提高界面的流畅度以及用户体验。我们务必要把耗时的操作放到别的线程中去执行,千万不要阻塞主线程。
iOS中有以下3种多线程编程方法:
Grand Centeral Dispatch(GCD)
NSOperation和NSOperationQueue
1.NSThread
这是最轻量级的多线程的方法,使用起来最直观的多线程编程方法。但是因为需要自己管理线程的生命周期,线程同步。经常使用NSThread进行调试,在实际项目中不推荐使用。
//获取当前线程
NSThread *current = [NSThread currentThread];
//获取主线程
NSThread *main = [NSThread mainThread];
NSLog(@&当前线程 --- %@&,current);
NSLog(@&主线程 --- %@&,main);
控制台输出结果:
22:30:29.572 多线程demo[] 当前线程 --- &NSThread: 0x7fc0e1401dc0&{number = 1, name = main}
22:30:29.572 多线程demo[] 主线程 --- &NSThread: 0x7fc0e1401dc0&{number = 1, name = main}
从结果我们看出当前的线程就是主线程,number相当于线程的id,name是线程的名称,主线程的number就是1
阻塞线程:
//阻塞线程3秒
[NSThread sleepForTimeInterval:3];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
2.GCD(Grand Central Dispatch)
GCD是基于C语言底层API实现的一套多线程并发机制,非常的灵活方便,在实际的开发中使用很广泛。
简单来说CGD就是把操作放在队列中去执行。
你只需定义好操作和队列就可以了,不需要直接控制线程的创建和销毁,线程的生命周期由队列来管理。
队列:负责操作的调度和执行,有先进先出(FIFO)的特点。也就是说先加入队列的操作先执行,后加入的后执行。
队列有两种:
串行队列:
队列中的操作只会按顺序执行,你可以想象成单窗口排队。
并行队列:
队列中的操作可能会并发执行,这取决与操作的类型,你可以想象成多窗口排队。
//创建串行队列
dispatch_queue_t q = dispatch_queue_create(&my_serial_queue&, DISPATCH_QUEUE_SERIAL);
//创建并行队列
dispatch_queue_t q = dispatch_queue_create(&my_concurrent_queue&, DISPATCH_QUEUE_CONCURRENT);
my_serial_queue和my_concurrent_queue是队列的名字标签,为了与其他的队列区分,在一个项目里面必须是唯一的。
DISPATCH_QUEUE_SERIAL表示串行队列
DISPATCH_QUEUE_CONCURRENT表示并行队列
操作同样也分两种类型:
同步操作:只会按顺序执行,执行顺序是确定的。
异步操作:在串行队列中执行顺序确定,在并行队列中执行顺序不确定
使用block来定义操作要执行的代码,q是已经定义好的,操作要加入的队列
//定义同步操作
dispatch_sync(q, ^{
//要执行的代码
//定义异步操作
dispatch_async(q, ^{
//要执行的代码
下面我们看一下同步,异步操作加入到串行和并行队列里面,执行的顺序和特点:
1.同步操作不管加入到何种队列,只会在主线程按顺序执行
dispatch_queue_t q_serial = dispatch_queue_create(&my_serial_queue&, DISPATCH_QUEUE_SERIAL);
dispatch_queue_t q_concurrent = dispatch_queue_create(&my_concurrent_queue&, DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i & 5; ++i) {
dispatch_sync(q_serial, ^{
NSLog(@&串行队列里的同步任务 %@ %d&, [NSThread currentThread], i);
for (int i = 0; i & 5; ++i) {
dispatch_sync(q_concurrent, ^{
NSLog(@&并行队列里的同步任务 %@ %d&, [NSThread currentThread], i);
下面是控制台输出结果:
00:40:36.862 01.GCD演练[] 串行队列里的同步任务 &NSThread: 0x7ff&{number = 1, name = main} 0
00:40:36.863 01.GCD演练[] 串行队列里的同步任务 &NSThread: 0x7ff&{number = 1, name = main} 1
00:40:36.863 01.GCD演练[] 串行队列里的同步任务 &NSThread: 0x7ff&{number = 1, name = main} 2
00:40:36.863 01.GCD演练[] 串行队列里的同步任务 &NSThread: 0x7ff&{number = 1, name = main} 3
00:40:36.863 01.GCD演练[] 串行队列里的同步任务 &NSThread: 0x7ff&{number = 1, name = main} 4
00:40:36.863 01.GCD演练[] 并行队列里的同步任务 &NSThread: 0x7ff&{number = 1, name = main} 0
00:40:36.863 01.GCD演练[] 并行队列里的同步任务 &NSThread: 0x7ff&{number = 1, name = main} 1
00:40:36.863 01.GCD演练[] 并行队列里的同步任务 &NSThread: 0x7ff&{number = 1, name = main} 2
00:40:36.864 01.GCD演练[] 并行队列里的同步任务 &NSThread: 0x7ff&{number = 1, name = main} 3
00:40:36.864 01.GCD演练[] 并行队列里的同步任务 &NSThread: 0x7ff&{number = 1, name = main} 4
2.异步操作只在非主线程的线程执行,在串行队列中异步操作会在新建的线程中按顺序执行。
dispatch_queue_t q_serial = dispatch_queue_create(&my_serial_queue&, DISPATCH_QUEUE_SERIAL);
for(int i = 0; i & 5; ++i){
dispatch_async(q_serial, ^{
NSLog(@&串行队列 -- 异步任务 %@ %d&, [NSThread currentThread], i);
因为是异步操作,所以会新建一个线程。又因为加入到串行队列中,所以所有的操作只会按顺序执行。
01:03:22.372 01.GCD演练[] 串行队列 -- 异步任务 &NSThread: 0x7fb593d42f50&{number = 2, name = (null)} 0
01:03:23.373 01.GCD演练[] 串行队列 -- 异步任务 &NSThread: 0x7fb593d42f50&{number = 2, name = (null)} 1
01:03:24.374 01.GCD演练[] 串行队列 -- 异步任务 &NSThread: 0x7fb593d42f50&{number = 2, name = (null)} 2
01:03:25.375 01.GCD演练[] 串行队列 -- 异步任务 &NSThread: 0x7fb593d42f50&{number = 2, name = (null)} 3
01:03:26.376 01.GCD演练[] 串行队列 -- 异步任务 &NSThread: 0x7fb593d42f50&{number = 2, name = (null)} 4
3.异步操作,并行队列
dispatch_queue_t q_concurrent = dispatch_queue_create(&my_concurrent_queue&, DISPATCH_QUEUE_CONCURRENT);
for(int i = 0; i & 5; ++i){
dispatch_async(q_concurrent, ^{
NSLog(@&并行队列 -- 异步任务 %@ %d&, [NSThread currentThread], i);
理论上并行队列会给每一个异步操作新建线程,然后让所有的任务并发执行。但是实际上系统能创建的线程数量是有限的,当创建的线程达到最大线程数以后,后面的异步操作就需要等待前面的操作执行完毕才能得到执行。哪个线程操作执行完毕,就把等待的异步任务安排到哪个线程。直到所有的操作执行完毕。
你可以把上述代码的循环次数改成5000就可以观察到此现象。
01:14:15.282 01.GCD演练[] 并行队列 -- 异步任务 &NSThread: 0x7fb3b841b0a0&{number = 4, name = (null)} 3
01:14:15.282 01.GCD演练[] 并行队列 -- 异步任务 &NSThread: 0x7fb3b8514da0&{number = 3, name = (null)} 0
01:14:15.282 01.GCD演练[] 并行队列 -- 异步任务 &NSThread: 0x7fb3b8604db0&{number = 5, name = (null)} 2
01:14:15.282 01.GCD演练[] 并行队列 -- 异步任务 &NSThread: 0x7fb3b86119d0&{number = 2, name = (null)} 1
01:14:15.285 01.GCD演练[] 并行队列 -- 异步任务 &NSThread: 0x7fb3b87011f0&{number = 6, name = (null)} 4
3.NSOperation & NSOperationQueue
虽然GCD的功能已经很强大了,但是它使用的API依然是C语言的。在某些时候,在面向对象的objective-c中使用起来非常的不方便和不安全。
所以苹果公司把GCD中的操作抽象成NSOperation对象,把队列抽象成NSOperationQueue对象。
抽象为NSOperation & NSOperationQueue以后的好处有一下几点:
代码风格统一了,我们不用在面向对象的objective-C中写面对过程的C语言代码了。
我们知道在GCD中操作的执行代码都是写在匿名的block里面,那么我们很难做到给操作设置依赖关系以及取消操作。这些功能都已经封装到NSOperation对象里面了。^-^
NSOperationQueue对象比GCD中队列更加的强大和灵活,比如:设置并发操作数量,取消队列中所有操作。
NSOperation分为NSInvocationOperation和NSBlockOperation
NSInvocationOperation的使用
//首先定义一个NSOperationQueue对象
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction:) object:@&这里可以穿参数&];
[queue addOperation:op];//把操作加入队列中即开始执行
- (void)operationAction:(id)obj
NSLog(@&%@ - obj : %@&, [NSThread currentThread], obj);
02:55:19.067 多线程demo[] &NSThread: 0x7f9dfa443510&{number = 2, name = (null)} - obj : 这里可以穿参数
NSBlockOperation的使用
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
[self operationAction:@&这是NSBlockOperation&];
[queue addOperation:op];
02:56:11.812 多线程demo[] &NSThread: 0x7fa983f10a50&{number = 2, name = (null)} - obj : 这是NSBlockOperation
设置依赖关系(执行顺序)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction:) object:@&op1&];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction:) object:@&op2&];
//op2在op1之后执行
[op2 addDependency:op1];//这里需要注意,一定要在addOperation之前设置依赖关系
[queue addOperation:op1];
[queue addOperation:op2];
02:57:40.283 多线程demo[] &NSThread: 0x7fb663e132d0&{number = 2, name = (null)} - obj : op1
02:57:40.284 多线程demo[] &NSThread: 0x7fb663e132d0&{number = 2, name = (null)} - obj : op2
没有设置依赖关系的输出:
03:00:45.939 多线程demo[] &NSThread: 0x7fe951d0d8a0&{number = 2, name = (null)} - obj : op2
03:00:45.939 多线程demo[] &NSThread: 0x7fe951c24720&{number = 3, name = (null)} - obj : op1
到这里你应该发现了,在NSOperation & NSOperationQueue中,我们不需要再像GCD那样定义操作的类型和队列的类型和控制操作的执行顺序了,你只需要直接设定操作的执行顺序就可以了。
阅读(...) 评论()iOS 多线程初学 - 多种方法创建多线程
首先介绍几个概念
1. 线程是进程的基本执行单元,一个进程的所有任务都是在线程中执行的。
2. 一个线程中的任务执行是串行的。
3. 每个进程都有至少一条线程,默认的线程为主线程。
1. 原理:同一时间,CPU 只能处理一条线程,意味着只有一条线程在工作。因为 CPU 的处理速度非常高,所以会产生很多空闲时间(时间碎皮)。多线程并发的原理,其实就是 CPU 快速的在多条线程之间调度。
2. 优点:提高程序执行效率。提高 CPU,内存等资源的利用效率。
3. 缺点:开启线程需要占用内存空间(一般主线程占1M,子线程占512K),如果开启大量子线程,会占用大量内存空间,降低系统性能。线程太多,CPU 调度就会非常频繁,加大 CPU 功耗。多线程也会使程序设计更加复杂,因为需要考虑到线程之间的通信和数据共享。
iOS 的开发与多线程:
一个 iOS 程序运行之后,会创建一条线程,称为“主线程”或者“UI线程”
主线程主要用于处理UI事件 显示,点击,滚动,拖拽 等等
耗时操作会卡主主线程,严重影响UI 的流畅度。
iOS 常用线程模型有如下四种
1. pthread - 纯 C 实现,使用率最低。作为了解即可,日常冷门装逼用。
2. NSThread - OC 线程库,实用率不高,仅作简单调用,比如获取当前线程什么的。
3. NSOperationQueue - 线程池/线程队列,实用率高,方便简洁高效。
4. GCD - Block 模式的线程池,C 实现,项目中也被广泛实用。
下面开实例 ================================
1. phread 简单的创建
需要引入头文件
#import &pthread.h&
pthread_create(&thread, NULL, run, NULL);
第一个参数是声明的线程变量地址,创建的线程会调用第三个函数指针指向的函数。
void * run() {
NSLog(@"奔跑, 线程: %@", [NSThread currentThread]);
return NULL;
函数中使用了 NSThread 的方法获取了当前的线程并打印出来。
运行结果:
20:43:31.230 ThreadTest[] 奔跑, 线程: &NSThread: 0x7f9f83597c50&{number = 2, name = (null)}通过结果可以看出,线程的 number 为 2 ,这意味着我们的函数并没有执行在 number 为 0 的主线程上,而是新开辟了一个线程。2. NSThread
用一个简单的例子来介绍NSThread 的几个常用的属性和方法。
- (void)viewDidLoad {
[super viewDidLoad];
NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
NSLog(@"这个输出证明虽然创建了 thread , 但是没有调用 start 就没办法自动执行。");
//如果需要让线程执行任务,需要调用 start 方法
[thread start];
- (void)run {
//[NSThread currentThread] 获取当前线程
NSLog(@"%@", [NSThread currentThread]);
//[NSThread isMultiThreaded] 判断是否为多线程
NSLog(@"%d", [NSThread isMultiThreaded]);
//[NSThread isMainThread] 判断当前线程是否为主线程
NSLog(@"%d", [NSThread isMainThread]);
}输出结果如下:
21:19:23.369 ThreadTest[] 这个输出证明虽然创建了 thread , 但是没有调用 start 就没办法自动执行。
21:19:23.390 ThreadTest[] &NSThread: 0x7fb98a496f20&{number = 2, name = (null)}
21:19:23.391 ThreadTest[] 1
21:19:23.391 ThreadTest[] 0从结果可以得知,在 start 方法被执行后,加入线程的任务被执行,即函数被调用,当前线程是多线程,且不是主线程。
GCD 弥补了 NSThread 难于管理的问题。
GCD 采用队列的方式管理线程
通过 GCD,开发者可以不用和线程打交道,而是直接向队列中扔代码Block 块就可以。
通过一个实例简单实现:
//创建一个 GCD 队列
dispatch_queue_t myQueue = dispatch_queue_create("myQueue", NULL);
dispatch_queue_t myQueue2 = dispatch_queue_create("myQueue2", NULL);
dispatch_async(myQueue, ^{
NSLog(@"myQueue - currentThread:%@, ",[NSThread currentThread]);
dispatch_async(myQueue2, ^{
NSLog(@"myQueue2 - currentThread:%@, ",[NSThread currentThread]);
});执行打印结果如下:
21:37:42.086 ThreadTest[] myQueue - currentThread:&NSThread: 0x7fac095bffa0&{number = 2, name = (null)},
21:37:42.086 ThreadTest[] myQueue2 - currentThread:&NSThread: 0x7fac&{number = 3, name = (null)}, 想要执行 GCD 的 dispatch_async 方法,必须把它交给一个队列管理,否则会报错。
dispatch_async 函数会把传入的 block 块放入指定的 queue 里面运行。这个函数是异步的,这就意味着它会立即返回而不管 block 块是否运行结束。
也可以通过获取全局变量的方式:
//获取全局队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_async(queue, ^{
NSLog(@"queue1:%@",[NSThread currentThread]);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSLog(@"queue2:%@",[NSThread currentThread]);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"queue3:%@",[NSThread currentThread]);
其中赋值的参数是优先级
运行结果:
21:46:00.726 ThreadTest[] queue2:&NSThread: 0x7fd&{number = 2, name = (null)}
21:46:00.728 ThreadTest[] queue3:&NSThread: 0x7fd2014ceb20&{number = 3, name = (null)}
21:46:00.729 ThreadTest[] queue1:&NSThread: 0x7fd&{number = 4, name = (null)}
4. NSOperationQueue
NSOperationQueue的底层就是基于 GCD 实现的,高度分装性使其具备更加易用的好处。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSInvocationOperation *iop = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];
NSBlockOperation *bop = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Block 任务 %@",[NSThread currentThread]);
[bop addExecutionBlock:^{
NSLog(@"新添加的任务 线程 : %@", [NSThread currentThread]);
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//把任务交给队列来执行和管理
[queue addOperation:iop];
[queue addOperation:bop];
- (void)run {
NSLog(@"Invocation 任务 线程:%@", [NSThread currentThread]);
}block方式 可以后续追加任务到 block 中。
执行结果如下:
21:55:13.282 ThreadTest[] Invocation 任务 线程:&NSThread: 0x7ff9e0cdd0b0&{number = 2, name = (null)}
21:55:13.282 ThreadTest[] Block 任务 &NSThread: 0x7ff9e0d7b320&{number = 3, name = (null)}
21:55:13.282 ThreadTest[] 新添加的任务 线程 : &NSThread: 0x7ff9e0d78910&{number = 4, name = (null)}
没有更多推荐了,二、代码示例
1.使用古老的方式创建
YYViewController.m
Created by apple on 14-6-23.
Copyright (c) 2014年 itcase. All rights reserved.
10 #import "YYViewController.h"
11 #import &pthread.h&
14 @interface YYViewController ()
15 - (IBAction)btnC
19 @implementation YYViewController
22 - (void)viewDidLoad
[super viewDidLoad];
28 //按钮的点击事件
29 - (IBAction)btnClick {
//1.获取当前线程
NSThread *current=[NSThread currentThread];
NSLog(@"btnClick----%@",current);
//2.使用for循环执行一些耗时操作
pthread_create(&thread, NULL, run, NULL);
41 //c语言函数
42 void *run(void *data)
//获取当前线程,是新创建出来的线程
NSThread *current=[NSThread currentThread];
for (int i=0; i&10000; i++) {
NSLog(@"btnClick---%d---%@",i,current);
return NULL;
54 //多个线程,点击按钮执行按钮调用方法的时候,主线程没有被阻塞
实现效果:
打印结果:
YYViewController.m
Created by apple on 14-6-23.
Copyright (c) 2014年 itcase. All rights reserved.
9 #import "YYViewController.h"
10 #import &pthread.h&
13 @interface YYViewController ()
14 - (IBAction)btnC
18 @implementation YYViewController
20 - (void)viewDidLoad
[super viewDidLoad];
26 //按钮的点击事件
27 - (IBAction)btnClick {
//1.获取当前线程
NSThread *current=[NSThread currentThread];
NSLog(@"btnClick----%@",current);
//获取主线程的另外一种方式
NSThread *main=[NSThread mainThread];
NSLog(@"主线程-------%@",main);
//2.执行一些耗时操作
[self creatNSThread];
[self creatNSThread2];
[self creatNSThread3];
* NSThread创建线程方式1
* 1& 先创建初始化线程
* 2& start开启线程
49 -(void)creatNSThread
*thread=[[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"线程A"];
//为线程设置一个名称
thread.name=@"线程A";
//开启线程
[thread start];
*thread2=[[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"线程B"];
//为线程设置一个名称
thread2.name=@"线程B";
//开启线程
[thread2 start];
* NSThread创建线程方式2
68 *创建完线程直接(自动)启动
71 -(void)creatNSThread2
NSThread *thread=[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"创建完线程直接(自动)启动"];
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"创建完线程直接(自动)启动"];
* NSThread创建线程方式3
* 隐式创建线程, 并且直接(自动)启动
84 -(void)creatNSThread3
//在后台线程中执行===在子线程中执行
[self performSelectorInBackground:@selector(run:) withObject:@"隐式创建"];
92 -(void)run:(NSString *)str
//获取当前线程
NSThread *current=[NSThread currentThread];
//打印输出
for (int i=0; i&10; i++) {
NSLog(@"run---%@---%@",current,str);
调用线程打印结果为:
随笔 - 196
评论 - 1494【ios 开启多线程执行任务】 - CSDN

我要回帖

更多关于 多线程 ios 的文章

 

随机推荐