Grand Central Dispatch (GCD)
Grand Central Dispatch (GCD) Reference
Grand Central Dispatch (GCD) comprises language features, runtime libraries, and system enhancements that provide systemic, comprehensive improvements to the support for concurrent code execution on multicore hardware in iOS and OS X.
GCD拥有丰富的语言特性,多样的运行库以及能增强系统效率,对于硬件上多核处理器提供了广泛地系统级别的优化,在多核的iOS OS X硬件体系中,高并发执行能力得到有效地提升.
The BSD subsystem, CoreFoundation, and Cocoa APIs have all been extended to use these enhancements to help both the system and your application to run faster, more efficiently, and with improved responsiveness. Consider how difficult it is for a single application to use multiple cores effectively, let alone doing it on different computers with different numbers of computing cores or in an environment with multiple applications competing for those cores. GCD, operating at the system level, can better accommodate the needs of all running applications, matching them to the available system resources in a balanced fashion.
BSD子系统,CoreFoundation以及Cocoa中的许多APIs都已经大量使用这些新的特性来帮助系统以及你的应用程序提升性能,使其运行得更快,提升交互体验.考虑到要让一款应用能够很有效地利用多核处理器,不管是在不同的电脑上(这个电脑有着不同数量的处理器)或者是同一台电脑上不同应用如何分配多个处理器.GCD,在系统级别上进行运作,能够很好地对所有运行中的程序进行优化,让他们充分利用系统资源的同时,达到一个美妙的平衡.
以上是官方文档前两段的翻译,正如描述中所说,GCD偏向系统调用,更加偏向于底层的函数,效率很高,我将我对于GCD使用的理解加以汇总.
线程是最小的执行单位,而线程需要在指定的线程池中才能够执行,以下是创建线程池的方法.
dispatch_queue_t dispatch_queue_create(
const char *label
dispatch_queue_attr_t attr);
#pragma mark - 创建并行队列线程池,任务并发执行,一起执行
NS_INLINE dispatch_queue_t GCD_create_concurrent_queue(NSString *queueName)
{
// DISPATCH_QUEUE_CONCURRENT
// 线程池提供多个线程来执行任务,所以可以按序启动多个任务并发执行
dispatch_queue_t concurrentQ
= dispatch_queue_create([queueName cStringUsingEncoding:NSUTF8StringEncoding],
DISPATCH_QUEUE_CONCURRENT);
return concurrentQ;
}
#pragma mark - 创建串行队列线程池,任务依次执行,上一个执行完毕才会执行下一个任务
NS_INLINE dispatch_queue_t GCD_create_serial_queue(NSString *queueName)
{
// DISPATCH_QUEUE_SERIAL
// 线程池只提供一个线程用来执行任务,所以后一个任务必须等到前一个任务执行结束才能开始(已经测试,一个任务执行完毕后才回去执行另外一个任务)
dispatch_queue_t serialQ
= dispatch_queue_create([queueName cStringUsingEncoding:NSUTF8StringEncoding],
DISPATCH_QUEUE_SERIAL);
return serialQ;
}
#pragma mark - 销毁线程池
NS_INLINE void GCD_release_queue(dispatch_queue_t queue)
{
#if __has_feature(objc_arc)
#else
dispatch_release(queue);
#endif
}
以下是创建一个单一线程的方法
#pragma mark - 在指定的线程池中执行该线程
NS_INLINE void GCD_dispatch_async(dispatch_queue_t queue, void (^block)())
{
//在指定的线程池中执行操作
dispatch_async(queue, ^{
block();
});
}
串行线程池
并发线程池
系统默认就有一个串行队列main_queue和并行队列global_queue,我对其进行了宏定义
// 系统子线程池(并发执行)
#define SYS_CONCURRENT_QUEUE_H dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
#define SYS_CONCURRENT_QUEUE_D dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define SYS_CONCURRENT_QUEUE_L dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
#define SYS_CONCURRENT_QUEUE_B dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)
// 系统主线程池(序列执行)
#define SYS_SERIAL_QUEUE dispatch_get_main_queue()
所以,一般是这么用的,子线程处理数据,结束后把数据传递到主线程,让主线程来更新UI
GCD_dispatch_async(SYS_CONCURRENT_QUEUE_L, ^{
// long-running task code here
GCD_dispatch_async(SYS_SERIAL_QUEUE, ^{
// update UI code here
});
});
线程的延时操作
#pragma mark - [GCD] 执行某种线程池中的延时操作
NS_INLINE void GCD_DelaySeconds(int64_t seconds, dispatch_queue_t queue, void (^block)(dispatch_queue_t queue))
{
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC);
dispatch_after(popTime, queue, ^(void){
block(queue);
});
}
线程组
#define SYS_CREATE_GROUP dispatch_group_create()
#pragma mark - 线程组,用以监听所有的线程是否已经执行完毕了
NS_INLINE void GCD_dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, void (^block)())
{
dispatch_group_async(group, queue, block);
}
以下是测试依次执行任务(线程)的代码以及结果,从现象以及结果可以看出,只有一个任务完整地执行完毕后才会执行下一个任务,这种线程池一次只处理一个任务
NS_INLINE NSData * dataFromNetUrlPath(NSString *path)
{
//网络数据URL
return [NSData dataWithContentsOfURL:[NSURL URLWithString:path]];
}
以下是测试并发执行任务(线程)的代码以及结果
即使是延时的操作都存在序列执行以及并发执行的区别,看结果
group也存在并发非并发问题,如下所示
GCD定时器
#pragma mark - 创建定时器
NS_INLINE dispatch_source_t GCD_create_timer(int64_t seconds, dispatch_queue_t queue, void (^block)(dispatch_source_t timer))
{
//创建Timer
dispatch_source_t _timer =
dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//使用dispatch_source_set_timer函数设置timer参数
dispatch_source_set_timer(_timer,
dispatch_time(DISPATCH_TIME_NOW, 0),
seconds * NSEC_PER_SEC,
0);
//设置回调
dispatch_source_set_event_handler(_timer, ^(){
block(_timer);
});
//dispatch_source默认是Suspended状态,通过dispatch_resume函数开始它
dispatch_resume(_timer);
return _timer;
}
#pragma mark - 销毁定时器(记得释放定时器,ARC与非ARC都支持)
NS_INLINE void GCD_release_timer(dispatch_source_t timer)
{
#if __has_feature(objc_arc)
#else
dispatch_release(timer);
#endif
}
GCD注意事项:
1. 选用了系统主线程池 dispatch_get_main_queue() 后,如果在这个线程池中执行了阻塞操作(例如执行了网络请求,但没有网络链接,网络超时),是会阻塞UI界面效果的,虽然,表面上看起来,启动了这个线程后就接着往下面执行了,这也说明了一个问题,UI控件的加载都是在主线程池中加载的,而主线程池本身就是串行线程池,所以,如果你写的代码在 dispatch_get_main_queue() 有着阻塞操作,会直接影响用户体验.
2. 同步线程 dispatch_sync 可以理解为一个代码块,必须执行完这个代码块之后才能往下面执行,但是,它不能在当前的线程池中执行,否则会造成死锁,要说用途,本人还没有研究出来^_^......
Calls to dispatch_sync() targeting the current queue will result in dead-lock
附录:
以下是本人自己封装的GCD类,支持ARC与非ARC,包含了GCD的queue,group以及semaphore,其属于初级封装,但见名知意.
提供源码以及使用方法如下
YXGCD.h
//
// YXGCD.h
//
// http://home.cnblogs.com/u/YouXianMing/
//
// Created by YouXian on 14-4-9.
// Copyright (c) 2014年 Y.X. All rights reserved.
// #import <Foundation/Foundation.h> // 系统子线程池(并发执行)
#define SYS_CONCURRENT_QUEUE_H dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
#define SYS_CONCURRENT_QUEUE_D dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define SYS_CONCURRENT_QUEUE_L dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
#define SYS_CONCURRENT_QUEUE_B dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) // 系统主线程池(序列执行)
#define SYS_SERIAL_QUEUE dispatch_get_main_queue()
#define SYS_UI_QUEUE dispatch_get_main_queue() //优先级枚举类型
typedef enum { HIGH_PRIORITY = DISPATCH_QUEUE_PRIORITY_HIGH,
LOW_PRIORITY = DISPATCH_QUEUE_PRIORITY_LOW,
DEFAULT_PRIORITY = DISPATCH_QUEUE_PRIORITY_DEFAULT,
BACKGROUND_PRIORITY = DISPATCH_QUEUE_PRIORITY_BACKGROUND, } QUEUE_PRIORITY; @interface YXGCD : NSObject #pragma mark - GCD_queue
+ (dispatch_queue_t)createSerialQueueWithName:(NSString *)name;
+ (dispatch_queue_t)createConcurrentQueueWithName:(NSString *)name;
+ (void)releaseQueue:(dispatch_queue_t)queue;
+ (void)asyncInQueue:(dispatch_queue_t)queue block:(void (^)())block;
+ (void)syncInQueue:(dispatch_queue_t)queue block:(void (^)())block;
+ (void)queue:(dispatch_queue_t)queue
asyncInGroup:(dispatch_group_t)group
block:(void (^)())block;
+ (void)queue:(dispatch_queue_t)queue
notifyInGroup:(dispatch_group_t)group
block:(void (^)())block; #pragma mark - GCD_group
+ (dispatch_group_t)createGroup;
+ (void)releaseGroup:(dispatch_group_t)group;
+ (void)enterGroup:(dispatch_group_t)group;
+ (void)leaveGroup:(dispatch_group_t)group;
+ (void)waitGroup:(dispatch_group_t)group;
+ (void)explicitlyIndicatesGroup:(dispatch_group_t)group
asyncInQueue:(dispatch_queue_t)queue
block:(void (^)())block;
+ (void)waitGroup:(dispatch_group_t)group
asyncInQueue:(dispatch_queue_t)queue
before:(void (^)())before
after:(void (^)())after;
+ (void)waitGroup:(dispatch_group_t)group
forTime:(int64_t)time
asyncInQueue:(dispatch_queue_t)queue
before:(void (^)())before
after:(void (^)(long result))after; #pragma mark - GCD_semaphore
+ (dispatch_semaphore_t)createSemaphoreWithValue:(long)value;
+ (void)releaseSemaphore:(dispatch_semaphore_t)semaphore;
+ (void)signalForSemaphore:(dispatch_semaphore_t)semaphore;
+ (void)waitForSemaphore:(dispatch_semaphore_t)semaphore;
+ (void)waitForSemaphore:(dispatch_semaphore_t)semaphore forTime:(int64_t)time; @end
YXGCD.m
//
// YXGCD.m
//
// http://home.cnblogs.com/u/YouXianMing/
//
// Created by YouXian on 14-4-9.
// Copyright (c) 2014年 Y.X. All rights reserved.
// #import "YXGCD.h" @implementation YXGCD + (void)asyncInQueue:(dispatch_queue_t)queue block:(void (^)())block
{
dispatch_async(queue, ^{
block();
});
} + (void)syncInQueue:(dispatch_queue_t)queue block:(void (^)())block
{
dispatch_sync(queue, ^{
block();
});
} + (void)asyncInBackgroundWithPriority:(QUEUE_PRIORITY)type block:(void (^)())block
{
dispatch_async(dispatch_get_global_queue(type, ), ^{
block();
});
} + (dispatch_queue_t)createSerialQueueWithName:(NSString *)name
{
dispatch_queue_t serialQ
= dispatch_queue_create([name cStringUsingEncoding:NSUTF8StringEncoding],
DISPATCH_QUEUE_SERIAL); return serialQ;
} + (dispatch_queue_t) createConcurrentQueueWithName:(NSString *)name
{
dispatch_queue_t concurrentQ
= dispatch_queue_create([name cStringUsingEncoding:NSUTF8StringEncoding],
DISPATCH_QUEUE_CONCURRENT); return concurrentQ;
} + (void)asyncInGroup:(dispatch_group_t)group
inQueue:(dispatch_queue_t)queue
block:(void (^)())block
{
dispatch_group_async(group, queue, block);
} + (void)queue:(dispatch_queue_t)queue
asyncInGroup:(dispatch_group_t)group
block:(void (^)())block
{
dispatch_group_async(group, queue, block);
} + (void)queue:(dispatch_queue_t)queue
notifyInGroup:(dispatch_group_t)group
block:(void (^)())block
{
dispatch_group_notify(group, queue, ^{
block();
});
} + (dispatch_group_t)createGroup
{
return dispatch_group_create();
} + (void)enterGroup:(dispatch_group_t)group
{
dispatch_group_enter(group);
} + (void)leaveGroup:(dispatch_group_t)group
{
dispatch_group_leave(group);
} + (void)waitGroup:(dispatch_group_t)group
{
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
} + (void)explicitlyIndicatesGroup:(dispatch_group_t)group
asyncInQueue:(dispatch_queue_t)queue
block:(void (^)())block
{
dispatch_group_enter(group);
dispatch_async(queue, ^{
block();
dispatch_group_leave(group);
});
} + (void)waitGroup:(dispatch_group_t)group
asyncInQueue:(dispatch_queue_t)queue
before:(void (^)())before
after:(void (^)())after
{
dispatch_async(queue, ^{
before();
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
after();
});
} + (void)waitGroup:(dispatch_group_t)group
forTime:(int64_t)time
asyncInQueue:(dispatch_queue_t)queue
before:(void (^)())before
after:(void (^)(long result))after
{
dispatch_async(queue, ^{
before();
long result = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, time));
after(result);
});
} + (dispatch_semaphore_t)createSemaphoreWithValue:(long)value
{
return dispatch_semaphore_create(value);
} + (void)signalForSemaphore:(dispatch_semaphore_t)semaphore
{
dispatch_semaphore_signal(semaphore);
} + (void)waitForSemaphore:(dispatch_semaphore_t)semaphore
{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
} + (void)waitForSemaphore:(dispatch_semaphore_t)semaphore forTime:(int64_t)time
{
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, time));
} + (void)releaseSemaphore:(dispatch_semaphore_t)semaphore
{
#if __has_feature(objc_arc)
#else
dispatch_release(semaphore);
#endif
} + (void)releaseGroup:(dispatch_group_t)group
{
#if __has_feature(objc_arc)
#else
dispatch_release(group);
#endif
} + (void)releaseQueue:(dispatch_queue_t)queue
{
#if __has_feature(objc_arc)
#else
dispatch_release(queue);
#endif
} @end
用法:
在主线程中操作
[YXGCD asyncInQueue:SYS_UI_QUEUE block:^{
// 更新UI操作代码
}];
在子线程中操作
[YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 阻塞操作
}];
子线程阻塞操作,主线程更新UI
[YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 阻塞操作 [YXGCD asyncInQueue:SYS_UI_QUEUE block:^{
// 更新UI操作
}];
}];
创建一个串行线程池,执行完后释放线程池(英文解释的含义是,当所有的任务执行完毕后,才会销毁线程池)
/*
When your application no longer needs the dispatch queue, it should release
it with the dispatch_release function. Any pending blocks submitted to a
queue hold a reference to that queue, so the queue is not deallocated until
all pending blocks have completed.
*/ // 创建一个序列线程
dispatch_queue_t serialQueue = [YXGCD createSerialQueueWithName:@"Y.X."]; // 序列任务1
[YXGCD asyncInQueue:serialQueue block:^{
// 你的代码
}]; // 序列任务2
[YXGCD asyncInQueue:serialQueue block:^{
// 你的代码
}]; // 释放线程池
[YXGCD releaseQueue:serialQueue];
使用GCD-group实现线程的等待操作
// 创建一个GCD-group
dispatch_group_t group = [YXGCD createGroup]; // 系统主线程的一个任务,加入到了监听组中
[YXGCD queue:SYS_UI_QUEUE asyncInGroup:group block:^{
// 代码
}]; // 系统默认优先级的一个子线程任务,加入到了监听组中
[YXGCD queue:SYS_CONCURRENT_QUEUE_D asyncInGroup:group block:^{
// 代码
}]; // 系统默认优先级的一个子线程,监听上面的任务执行完毕后,才会执行任务
[YXGCD queue:SYS_CONCURRENT_QUEUE_D notifyInGroup:group block:^{
// 代码
}]; // 释放GCD-group
[YXGCD releaseGroup:group];
另外一种实现线程等待的方式
// 创建一个GCD-group
dispatch_group_t group = [YXGCD createGroup]; // 在系统默认子线程中执行代码,注意enterGroup与leaveGroup必须成对出现
[YXGCD enterGroup:group];
[YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 代码 [YXGCD leaveGroup:group];
}]; // 在系统主线程中执行代码,注意enterGroup与leaveGroup必须成对出现
[YXGCD enterGroup:group];
[YXGCD asyncInQueue:SYS_UI_QUEUE block:^{
// 代码 [YXGCD leaveGroup:group];
}]; // 在系统默认子线程中执行代码,等待上面的线程执行完毕
[YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
[YXGCD waitGroup:group];
// 上面两个线程执行完毕且leaveGroup后才会执行下面的代码
}]; // 释放线程组
[YXGCD releaseGroup:group];
封装了group的enter与leave操作,更简单易用
// 创建一个GCD-group
dispatch_group_t group = [YXGCD createGroup]; // 封装group的enter与leave操作
[YXGCD explicitlyIndicatesGroup:group asyncInQueue:SYS_UI_QUEUE block:^{
// 代码
}]; // 封装group的enter与leave操作
[YXGCD explicitlyIndicatesGroup:group asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 代码
}]; [YXGCD waitGroup:group asyncInQueue:SYS_CONCURRENT_QUEUE_D before:^{
// wait之前的操作
} after:^{
// 等到所有在组中的任务结束后,就会执行
}]; // 释放线程组
[YXGCD releaseGroup:group];
具有超时等待特性的group操作
// 创建一个GCD-group
dispatch_group_t group = [YXGCD createGroup]; // 封装group的enter与leave操作
[YXGCD explicitlyIndicatesGroup:group asyncInQueue:SYS_UI_QUEUE block:^{
// 代码
}]; // 封装group的enter与leave操作
[YXGCD explicitlyIndicatesGroup:group asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 代码
}]; // 等待3s,看所有组中的线程是否已经完成
[YXGCD waitGroup:group forTime: * NSEC_PER_SEC asyncInQueue:SYS_UI_QUEUE before:^{ } after:^(long result) {
if (result == )
{
NSLog(@"所有线程都完成了");
}
else
{
NSLog(@"有的线程没有完成,超时了");
}
}]; // 释放线程组
[YXGCD releaseGroup:group];
GCD信号量用法
// 创建一个信号量
dispatch_semaphore_t semaphore = [YXGCD createSemaphoreWithValue:]; [YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 连续5次发送信号量
for (int i = ; i < ; i++)
{
// 模拟阻塞操作1s
sleep(); // 发送信号量
[YXGCD signalForSemaphore:semaphore];
}
}]; [YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 死循环,不停等待接收信号量
while ()
{
// 阻塞等待接收信号量
[YXGCD waitForSemaphore:semaphore]; // 你的操作
NSLog(@"Y.X.");
} }]; // 释放信号量
[YXGCD releaseSemaphore:semaphore];
Grand Central Dispatch (GCD)的更多相关文章
- IOS 多线程编程之Grand Central Dispatch(GCD)介绍和使用 多线程基础和练习
介绍:前面内容源自网络 Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式 ...
- [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...
- iOS 多线程编程之Grand Central Dispatch(GCD)
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...
- Grand Central Dispatch(GCD)详解(转)
概述 GCD是苹果异步执行任务技术,将应用程序中的线程管理的代码在系统级中实现.开发者只需要定义想要执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务.由于 ...
- Grand Central Dispatch(GCD)详解
概述 GCD是苹果异步执行任务技术,将应用程序中的线程管理的代码在系统级中实现.开发者只需要定义想要执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务.由于 ...
- iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用
http://blog.csdn.net/totogo2010/article/details/8016129 GCD很好的博文
- NSThread 子线程 Cocoa NSOperation GCD(Grand Central Dispatch) 多线程
单词:thread 英 θred:n 线.思路.vt 穿过.vi 穿透过 一. 进程.线程 进程:正在进行中的程序被称为进程,负责程序运行的内存分配,每一个进程都有自己独立的虚拟内存空间 线程: ...
- iOS开发-多线程之GCD(Grand Central Dispatch)
Grand Central Dispatch(GCD)是一个强有力的方式取执行多线程任务,不管你在回调的时候是异步或者同步的,可以优化应用程序支持多核心处理器和其他的对称多处理系统的系统.开发使用的过 ...
- 在Swift中应用Grand Central Dispatch(上)转载自的goldenfiredo001的博客
尽管Grand Central Dispatch(GCD)已经存在一段时间了,但并非每个人都知道怎么使用它.这是情有可原的,因为并发很棘手,而且GCD本身基于C的API在 Swift世界中很刺眼. 在 ...
随机推荐
- spring websocket源码分析
什么是websocket? 摘录于wiki[1]: WebSocket is a protocol providing full-duplex communication channels over ...
- Android View中的控件和监听方法...
PS:居然三天没写博客了...今天补上...东西虽多,但是都是一些基础...代码多了一些,有人可能会这样问,粘这么多代码有毛用..其实对于一个Android的初学者来说,一个完整的代码是最容易帮助理解 ...
- Mysql学习笔记(十四)备份与恢复
学习内容: 1.数据库的重要数据备份... 2.什么时候需要使用到数据库备份.. 3.如何恢复备份的数据.. 1.备份: 说到备份,相比大家都不应该陌生,比如说我们平时在为我们的电脑重新做系统的时候, ...
- NetworkComms.Net github下载地址
https://github.com/MarcFletcher/NetworkComms.Net
- 面向对象的Javascript(5):继承
在小项目中对于JavaScript使用,只要写几个function就行了.但在大型项目中,尤其是在开发追求 良好的用户体验的网站中,如SNS,就会 用到大量的JavaScrpt,有时JavaScrip ...
- Ext.NET 4.1.0 GridPanel数据分页
针对大量数据在前端展示,需要进行分页显示,这里我使用的数据量为100万,数据存储在MongoDb中(也可以存储在本地文件或其它数据库中).最终显示效果如下: 步骤如下: 1.新建程序并配置,详见htt ...
- 字典树(Trie树)实现与应用
一.概述 1.基本概念 字典树,又称为单词查找树,Tire数,是一种树形结构,它是一种哈希树的变种. 2.基本性质 根节点不包含字符,除根节点外的每一个子节点都包含一个字符 从根节点到某一节点.路径上 ...
- 404 Not Found错误页面的解决方法和注意事项
最近这段时间一直忙于整理网站的错误页面,期间整理了很多关于404 Not Found错误页面的知识,加之最近也在帮团队新来的人员培训seo优化知识,所以在此借助马海祥博客的平台就拿出来跟大家一起分享一 ...
- C#中 导入和导出Excel的方法
using System.Data; using System.Data.OleDb; /// <summary> /// Excel转为DataTable /// </summar ...
- javascript:Bing Maps AJAX Control, Version 7.0
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...