2017-04-20 13 views
1

背景RxSwift - 斯普利特顺序分成较小的序列Concat的上

我想实现通过下载使用Range头块的文件。

目标

我想利用http请求的一个大的序列插入,我可以然后向的concat一次处理4个请求四个序列。

当前人大常委会

我目前考虑我的程序和使用concat保证之前,我开始了第二次观察到的第一个请求完成。这样做的目的是为了确保我不会因为请求过多而超负荷阿拉莫菲尔,从而最终导致请求超时。

理想情况下,我想将我的序列分成四个相当的序列,因为Alamofire设置为一次处理与主机的四个连接。我想这样做,因为我相信这会增加我的下载速度。

下载文件使用大块

Observable.generate(initialState: 0, condition: { $0 < fileSize }, iterate: {$0 + self.defaultChunkSize}) 
    .map({ (startChunk) in 
     let endChunk = startChunk + self.defaultChunkSize > fileSize ? fileSize : startChunk + self.defaultChunkSize 

     return (startChunk, endChunk) 
    }) 
    .map({ (startChunk: Int, endChunk: Int) -> Observable<FileChunkResult> in 
     self.filesClient.downloadChunkOf(fileId: file.id, startChunk: Int64(startChunk), endChunk: Int64(endChunk)) 
    }) 

    .concat() // <----- This is where I am forcing the large sequence to do one observable at a time 

    .flatMap({ (result: FileChunkResult) -> Observable<FileSaveChunkResult> in 
     switch (result) { 
     case FileChunkResult.success(let chunkData): 
      return self.saveChunkToFile(fileChunk: chunkData, location: urlToSaveTo) 
     case FileChunkResult.failure: // Maybe change this to just default and return Observable.just(FileSaveChunkResult.failure) 
      break 
     case FileChunkResult.parserError: 
      break 
     } 

     return Observable.just(FileSaveChunkResult.failure) 
    }) 
    .flatMap({ (result: FileSaveChunkResult) -> Observable<Progress> in 
     switch (result) { 
     case FileSaveChunkResult.success(let bytesSaved): 
      progress.completedUnitCount += bytesSaved 
     case FileSaveChunkResult.failure: 
      break 
     } 

     return Observable.just(progress) 
    }) 
+0

只是一个供参考。 (1)AlamoFire没有任何限制你一次四个请求,虽然可能有一些关于你的服务器导致这样的限制。 (2)以最大1/4的速度并行上传的四个请求不太可能每个完成速度比按顺序上传四个请求更快。 –

回答

1

下面的代码将打碎大块入使用的concat四个相等大小的数组,以确保只有一个保存从每个阵列是活动的时间。这意味着无论某个特定的呼叫有多快或多快,您都将始终保持4 saveChunkToFile的呼叫。

换句话说,它立即启动四个请求,然后每当前一个请求完成时启动一个请求。

let generator = Observable.generate(initialState: 0, condition: { $0 < fileSize }, iterate: { $0 + defaultChunkSize }) 
let chunks = generator.map({ (startChunk) -> (Int64, Int64) in 
    let endChunk = (startChunk + defaultChunkSize > fileSize ? fileSize : startChunk + defaultChunkSize) 
    return (startChunk, endChunk) 
}) 

let count = ceil(Double(fileSize)/Double(defaultChunkSize)/4) 
let requests = chunks.window(timeSpan: 0.0, count: Int(count), scheduler: MainScheduler.instance) 
    .flatMap { $0 
     .map({ (startChunk: Int64, endChunk: Int64) -> Observable<FileChunk> in 
      return makeChunkRequest(url: downloadUrl, startChunk: startChunk, endChunk: endChunk) 
     }).concat() 
} 

let downloadObservable = requests 
    .flatMap({ (fileChunk: FileChunk) -> Observable<FileSaveChunkResult> in 
     return saveChunkToFile(fileChunk: fileChunk, location: localDestinationUrl) 
    }).flatMap({ (saveResult: FileSaveChunkResult) -> Observable<Progress> in 
     if case .success(let bytesSaved) = saveResult { 
      progress.completedUnitCount += bytesSaved 
     } 
     return Observable.just(progress) 
    }) 

_ = downloadObservable.subscribe(onNext: { print(Date(), $0) })