GCD 多线程(一)



利用GCD下载大量图片的Demo


GCD简介:

http://www.dreamingwish.com/dream-2012/gcd介绍(一)-基本概念和dispatch-queue.html

http://blog.csdn.net/liuhongwei123888/article/details/6899366

GCD不需要使用锁,但是可以用 用户队列(必须用用户队列[dispatch_queue_create ],而非全局队列) 替代锁来完成同步机制。然后可以用dispatch_async  或者 dispatch_sync 将共享数据的访问代码封装起来。

  1. - (id)something  
  2. {  
  3.     __block id localSomething;  
  4.     <span style="color:#ff0000;">dispatch_sync</span>(queue, ^{  
  5.         localSomething = [something retain];  
  6.     });  
  7.     return [localSomething autorelease];  
  8. }  
  9.   
  10. - (void)setSomething:(id)newSomething  
  11. {  
  12.     <span style="color:#ff0000;">dispatch_async</span>(queue, ^{  
  13.         if(newSomething != something)  
  14.         {  
  15.             [something release];  
  16.             something = [newSomething retain];  
  17.             [self updateSomethingCaches];  
  18.         }  
  19.     });  
  20. }  



dispatch_async 与 dispatch_get_global_queue的区别和联系:

dispatch_sync:提交块对象给指定的调剂队列,同步履行。
dispatch_async:提交块对象给指定的调剂队列,异步履行。
dispatch_async() 调用以后立即返回。
dispatch_sync() 调用以后等到block执行完以后才返回 。dispatch_sync()会阻塞当前线程。
[NSThread isMainThread]  是判断当前线程是否为主线程,

dispatch queue是一个对象,它可以接受任务,并将任务以先到先执行的顺序来执行。d ispatch queue可以是并发的或串行的。

GCD中有三种队列类型:

  1. The main queue: 与主线程功能相同。实际上,提交至main queue的任务会在主线程中执行。main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的,所以这是一个串行队列。
  2. Global queues: 全局队列是并发队列,并由整个进程共享。进程中存在三个全局队列:高、中(默认)、低三个优先级队列。可以调用dispatch_get_global_queue函数传入优先级来访问队列。
  3. 用户队列: 用户队列 (GCD并不这样称呼这种队列, 但是没有一个特定的名字来形容这种队列,所以我们称其为用户队列) 是用函数 dispatch_queue_create 创建的队列. 这些队列是串行的。正因为如此,它们可以用来完成同步机制, 有点像传统线程中的mutex。



创建队列:
要使用用户队列,我们首先得创建一个。调用函数dispatch_queue_create就行了。函数的第一个参数是一个标签,这纯是为了debug。第二个参数目前不支持,传入NULL就行。
提交Job:
向一个队列提交Job很简单:调用dispatch_async函数,传入一个队列和一个block。队列会在轮到这个block执行时执行这个block的代码。下面的例子是一个在后台执行一个巨长的任务://该方法不用等到block语法执行完,而是立马就返回,block会在后台异步执行。
  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
  2.        [self goDoSomethingLongAndInvolved];  
  3.        NSLog(@"Done doing something long and involved");  
  4. );  


在典型的Cocoa程序中,你很有可能希望在任务完成时更新界面,这就意味着需要在主线程中执行一些代码。你可以简单地完成这个任务——使用嵌套的dispatch,在外层中执行后台任务,在内层中将任务dispatch到main queue:代码如下:
  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
  2.         [self goDoSomethingLongAndInvolved];  
  3.         dispatch_async(dispatch_get_main_queue(), ^{  
  4.             [textField setStringValue:@"Done doing something long and involved"];  
  5.         });  
  6. });  
要用于同步机制,queue必须是一个用户队列,而非全局队列,所以使用using dispatch_queue_create 初始化一个。然后可以用 dispatch_async   或者  dispatch_sync 将共享数据的访问代码封装起来:

  1. <pre name="code" class="cpp">- (id)something   
  2. { __block id localSomething;  
  3.  dispatch_sync(queue, ^{ localSomething = [something retain];   
  4.             });   
  5.     return [localSomething autorelease];   
  6. }  
  7.  - (void)setSomething:(id)newSomething   
  8. { dispatch_async(queue, ^{  
  9.      if(newSomething != something)   
  10.          {  
  11.                    [something release];   
  12.           something = [newSomething retain];   
  13.         [self updateSomethingCaches];   
  14.         }   });   
  15. }</pre><br><br><br>  

 值得注意的是dispatch queue是非常轻量级的,就像你以前使用lock一样。

 
  1. //dispatch_get_global_queue()是全局队列,并发执行  
  2.  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),  ^{  
  3.      for (int i=0; i<100; i++) {  
  4.          float newProgress = [progressView progress] + 0.01;  
  5.          //刷新主线程  
  6.          dispatch_async(dispatch_get_main_queue(), ^{  
  7.              progressView.progress = newProgress;  
  8.          });  
  9.          usleep(1000*100);  
  10.      } //for loop  
  11.  });//dispatch_async  

有时候我们有一段代码要像这样操作一个数组,但是在操作完成后,我们还需要对操作结果进行其他操作:

  1. for(id obj in array)  
  2.     [self doSomethingIntensiveWith:obj];  
  3.  [self doSomethingWith:array];  

这时候使用GCD的dispatch_async 就悲剧了,我们还不能简单的使用dispatch_sync来解决这个问题,因为这将导致每个迭代器阻塞,就完全破坏了平行计算。


A:用三个线程串行执行做一件事,完成之后回调finish方法。

B:把三个线程放在group里面,完成之后回调finish方法。

A和B的区别是:A三个线程是串行的而B三个线程是并行的,都是在线程完成之后回调finish的方法。


决这个问题的一种方法是使用dispatch group。一个dispatch group可以用来将多个block组成一组以监测这些Block全部完成或者等待全部完成时发出的消息使用函数dispatch_group_create来创建,然后使用函数dispatch_group_async来将block提交至一个dispatch queue,同时将它们添加至一个组。所以我们现在可以重新编码:

  1. dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
  2. dispatch_group_t group = dispatch_group_create();  
  3. for(id obj in array)  
  4.     dispatch_group_async(group, queue, ^{  
  5.         [self doSomethingIntensiveWith:obj];  
  6.     });  
  7. dispatch_group_wait(group, DISPATCH_TIME_FOREVER);  
  8. dispatch_release(group);  
  9.    
  10. [self doSomethingWith:array];  
如果这些工作可以异步执行,那么我们可以更风骚一点,将函数 -doSomethingWith:放在后台执行。我们使用dispatch_group_async函数建立一个block在组完成后执行:

  1. dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
  2. dispatch_group_t group = dispatch_group_create();  
  3. for(id obj in array)  
  4.     dispatch_group_async(group, queue, ^{  
  5.         [self doSomethingIntensiveWith:obj];  
  6.     });  
  7. dispatch_group_notify(group, queue, ^{  
  8.     [self doSomethingWith:array];  
  9. });  
  10. dispatch_release(group);  
不仅所有数组元素都会被平行操作,后续的操作也会异步执行,并且这些异步运算都会将程序的其他部分的负载考虑在内。注意如果 -doSomethingWith:需要在主线程中执行,比如操作GUI,那么我们只要将main queue而非全局队列传给dispatch_group_notify函数就行了。


对于同步执行,GCD提供了一个简化方法叫做dispatch_apply。这个函数调用单一block多次,并平行运算,然后等待所有运算结束,就像我们想要的那样

  1. dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
  2.     dispatch_apply([array count], queue, ^(size_t index){  
  3.         [self doSomethingIntensiveWith:[array objectAtIndex:index]];  
  4.     });  
  5.     [self doSomethingWith:array];  

这很棒,但是异步咋办?dispatch_apply函数可是没有异步版本的。但是我们使用的可是一个为异步而生的API啊!所以我们只要用dispatch_async函数将所有代码推到后台就行了:

  1. dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
  2. dispatch_async(queue, ^{  
  3.     dispatch_apply([array count], queue, ^(size_t index){  
  4.         [self doSomethingIntensiveWith:[array objectAtIndex:index]];  
  5.     });  
  6.     [self doSomethingWith:array];  
  7. });  

dispatch_group_wait(group,timeout) 与 dispatch_group_notify 的区别:
之后我试了以下 dispatch_group_wait( .. , .. ) 这个函数
把dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{ });
替换成:  dispatch_group_wait (group, DISPATCH_TIME_FOREVER );
再在最后加上   dispatch_release (group);     
//因为官方文档中说group 不再用时release,但是在creat函数中没有特殊说明需要release , 加上release之后测试了几次也没报错, 想下就先加上了。

实现的功能和之前一样,再说下 dispatch_group_wait (group,  timeout ) 这个函数,
第一个参数是:需要等待的group。
第二个参数是:设定的等待时间。
效果: 等待group是否为空group,如果在timeout时间内group为空了,则返回0;否则返回非0。 如果timeout为 DISPATCH_TIME_FOREVER,那就是一直阻塞着,直到group内内容完全处理完在执行。

书中例子用到的 dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{});
则是表示 指定一个额外的程序块,它将在group中的所有程序块即将运行完成时 再执行。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
GeoPandas是一个开源的Python库,旨在简化地理空间数据的处理和分析。它结合了Pandas和Shapely的能力,为Python用户提供了一个强大而灵活的工具来处理地理空间数据。以下是关于GeoPandas的详细介绍: 一、GeoPandas的基本概念 1. 定义 GeoPandas是建立在Pandas和Shapely之上的一个Python库,用于处理和分析地理空间数据。 它扩展了Pandas的DataFrame和Series数据结构,允许在其中存储和操作地理空间几何图形。 2. 核心数据结构 GeoDataFrame:GeoPandas的核心数据结构,是Pandas DataFrame的扩展。它包含一个或多个列,其中至少一列是几何列(geometry column),用于存储地理空间几何图形(如点、线、多边形等)。 GeoSeries:GeoPandas中的另一个重要数据结构,类似于Pandas的Series,但用于存储几何图形序列。 二、GeoPandas的功能特性 1. 读取和写入多种地理空间数据格式 GeoPandas支持读取和写入多种常见的地理空间数据格式,包括Shapefile、GeoJSON、PostGIS、KML等。这使得用户可以轻松地从各种数据源中加载地理空间数据,并将处理后的数据保存为所需的格式。 2. 地理空间几何图形的创建、编辑和分析 GeoPandas允许用户创建、编辑和分析地理空间几何图形,包括点、线、多边形等。它提供了丰富的空间操作函数,如缓冲区分析、交集、并集、差集等,使得用户可以方便地进行地理空间数据分析。 3. 数据可视化 GeoPandas内置了数据可视化功能,可以绘制地理空间数据的地图。用户可以使用matplotlib等库来进一步定制地图的样式和布局。 4. 空间连接和空间索引 GeoPandas支持空间连接操作,可以将两个GeoDataFrame按照空间关系(如相交、包含等)进行连接。此外,它还支持空间索引,可以提高地理空间数据查询的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值