Skip to content

Commit 7bc087b

Browse files
authored
Merge pull request SDWebImage#3460 from dreampiggy/feat/ioqueue_concurrent_config
Added `ioQueueAttributes` to use concurrent or control QoS for image cache internal IO Queue
2 parents 0274aa8 + ffc9166 commit 7bc087b

File tree

4 files changed

+38
-3
lines changed

4 files changed

+38
-3
lines changed

SDWebImage/Core/SDImageCache.m

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,16 @@ - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns
109109
if ((self = [super init])) {
110110
NSAssert(ns, @"Cache namespace should not be nil");
111111

112-
// Create IO serial queue
113-
_ioQueue = dispatch_queue_create("com.hackemist.SDImageCache", DISPATCH_QUEUE_SERIAL);
114-
115112
if (!config) {
116113
config = SDImageCacheConfig.defaultCacheConfig;
117114
}
118115
_config = [config copy];
119116

117+
// Create IO queue
118+
dispatch_queue_attr_t ioQueueAttributes = _config.ioQueueAttributes;
119+
_ioQueue = dispatch_queue_create("com.hackemist.SDImageCache", ioQueueAttributes);
120+
NSAssert(_ioQueue, @"The IO queue should not be nil. Your configured `ioQueueAttributes` may be wrong");
121+
120122
// Init the memory cache
121123
NSAssert([config.memoryCacheClass conformsToProtocol:@protocol(SDMemoryCache)], @"Custom memory cache class must conform to `SDMemoryCache` protocol");
122124
_memoryCache = [[config.memoryCacheClass alloc] initWithConfig:_config];

SDWebImage/Core/SDImageCacheConfig.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,15 @@ typedef NS_ENUM(NSUInteger, SDImageCacheConfigExpireType) {
127127
*/
128128
@property (strong, nonatomic, nullable) NSFileManager *fileManager;
129129

130+
/**
131+
* The dispatch queue attr for ioQueue. You can config the QoS and concurrent/serial to internal IO queue. The ioQueue is used by SDImageCache to access read/write for disk data.
132+
* Defaults we use `DISPATCH_QUEUE_SERIAL`(NULL), to use serial dispatch queue to ensure single access for disk data. It's safe but may be slow.
133+
* @note You can override this to use `DISPATCH_QUEUE_CONCURRENT`, use concurrent queue.
134+
* @warning **MAKE SURE** to keep `diskCacheWritingOptions` to use `NSDataWritingAtomic`, or concurrent queue may cause corrupted disk data (because multiple threads read/write same file without atomic is not IO-safe).
135+
* @note This value does not support dynamic changes. Which means further modification on this value after cache initialized has no effect.
136+
*/
137+
@property (strong, nonatomic, nullable) dispatch_queue_attr_t ioQueueAttributes;
138+
130139
/**
131140
* The custom memory cache class. Provided class instance must conform to `SDMemoryCache` protocol to allow usage.
132141
* Defaults to built-in `SDMemoryCache` class.

SDWebImage/Core/SDImageCacheConfig.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ - (instancetype)init {
3535
_maxDiskAge = kDefaultCacheMaxDiskAge;
3636
_maxDiskSize = 0;
3737
_diskCacheExpireType = SDImageCacheConfigExpireTypeModificationDate;
38+
_fileManager = nil;
39+
_ioQueueAttributes = DISPATCH_QUEUE_SERIAL; // NULL
3840
_memoryCacheClass = [SDMemoryCache class];
3941
_diskCacheClass = [SDDiskCache class];
4042
}
@@ -56,6 +58,7 @@ - (id)copyWithZone:(NSZone *)zone {
5658
config.maxMemoryCount = self.maxMemoryCount;
5759
config.diskCacheExpireType = self.diskCacheExpireType;
5860
config.fileManager = self.fileManager; // NSFileManager does not conform to NSCopying, just pass the reference
61+
config.ioQueueAttributes = self.ioQueueAttributes; // Pass the reference
5962
config.memoryCacheClass = self.memoryCacheClass;
6063
config.diskCacheClass = self.diskCacheClass;
6164

Tests/Tests/SDImageCacheTests.m

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,27 @@ - (void)test47DiskCacheExtendedData {
650650
[self waitForExpectationsWithCommonTimeout];
651651
}
652652

653+
- (void)test48CacheUseConcurrentIOQueue {
654+
XCTestExpectation *expectation = [self expectationWithDescription:@"SDImageCache concurrent ioQueue"];
655+
expectation.expectedFulfillmentCount = 2;
656+
657+
SDImageCacheConfig *config = [SDImageCacheConfig new];
658+
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_BACKGROUND, 0);
659+
config.ioQueueAttributes = attr;
660+
661+
SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"Concurrent" diskCacheDirectory:@"/" config:config];
662+
NSData *pngData = [NSData dataWithContentsOfFile:[self testPNGPath]];
663+
[cache queryCacheOperationForKey:@"Key1" done:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) {
664+
expect(data).beNil();
665+
[expectation fulfill];
666+
}];
667+
[cache storeImageData:pngData forKey:@"Key1" completion:^{
668+
[expectation fulfill];
669+
}];
670+
671+
[self waitForExpectationsWithCommonTimeout];
672+
}
673+
653674
#pragma mark - SDImageCache & SDImageCachesManager
654675
- (void)test49SDImageCacheQueryOp {
655676
XCTestExpectation *expectation = [self expectationWithDescription:@"SDImageCache query op works"];

0 commit comments

Comments
 (0)