- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在使用 URLSession 和 downloadTask 在前台下载文件。下载比预期慢得多。我发现的其他帖子解决了后台任务的问题。
let config = URLSessionConfiguration.default
config.httpMaximumConnectionsPerHost = 20
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
let request = URLRequest(url: url)
let completion: ((URL?, Error?) -> Void) = { (tempLocalUrl, error) in
print("Download over")
}
value.completion = completion
value.task = self.session.downloadTask(with: request)
我观察到网络使用量约为 150kb/s,而我设备上的速度测试报告连接速度为 5MB/s
=== 编辑
我可以确认编码分段下载(这做起来有点痛苦)可以大大加快速度。
最佳答案
如果这对任何人有帮助,这里是我的代码来加速下载。它将文件下载拆分为多个文件部分下载,从而更有效地使用可用带宽。必须这样做仍然感觉不对...
最终的用法是这样的:
// task.pause is not implemented yet
let task = FileDownloadManager.shared.download(from:someUrl)
task.delegate = self
task.resume()
代码如下:
/// Holds a weak reverence
class Weak<T: AnyObject> {
weak var value : T?
init (value: T) {
self.value = value
}
}
enum DownloadError: Error {
case missingData
}
/// Represents the download of one part of the file
fileprivate class DownloadTask {
/// The position (included) of the first byte
let startOffset: Int64
/// The position (not included) of the last byte
let endOffset: Int64
/// The byte length of the part
var size: Int64 { return endOffset - startOffset }
/// The number of bytes currently written
var bytesWritten: Int64 = 0
/// The URL task corresponding to the download
let request: URLSessionDownloadTask
/// The disk location of the saved file
var didWriteTo: URL?
init(for url: URL, from start: Int64, to end: Int64, in session: URLSession) {
startOffset = start
endOffset = end
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.allHTTPHeaderFields?["Range"] = "bytes=\(start)-\(end - 1)"
self.request = session.downloadTask(with: request)
}
}
/// Represents the download of a file (that is done in multi parts)
class MultiPartsDownloadTask {
weak var delegate: MultiPartDownloadTaskDelegate?
/// the current progress, from 0 to 1
var progress: CGFloat {
var total: Int64 = 0
var written: Int64 = 0
parts.forEach({ part in
total += part.size
written += part.bytesWritten
})
guard total > 0 else { return 0 }
return CGFloat(written) / CGFloat(total)
}
fileprivate var parts = [DownloadTask]()
fileprivate var contentLength: Int64?
fileprivate let url: URL
private var session: URLSession
private var isStoped = false
private var isResumed = false
/// When the download started
private var startedAt: Date
/// An estimate on how long left before the download is over
var remainingTimeEstimate: CGFloat {
let progress = self.progress
guard progress > 0 else { return CGFloat.greatestFiniteMagnitude }
return CGFloat(Date().timeIntervalSince(startedAt)) / progress * (1 - progress)
}
fileprivate init(from url: URL, in session: URLSession) {
self.url = url
self.session = session
startedAt = Date()
getRemoteResourceSize().then { [weak self] size -> Void in
guard let wself = self else { return }
wself.contentLength = size
wself.createDownloadParts()
if wself.isResumed {
wself.resume()
}
}.catch { [weak self] error in
guard let wself = self else { return }
wself.isStoped = true
}
}
/// Start the download
func resume() {
guard !isStoped else { return }
startedAt = Date()
isResumed = true
parts.forEach({ $0.request.resume() })
}
/// Cancels the download
func cancel() {
guard !isStoped else { return }
parts.forEach({ $0.request.cancel() })
}
/// Fetch the file size of a remote resource
private func getRemoteResourceSize(completion: @escaping (Int64?, Error?) -> Void) {
var headRequest = URLRequest(url: url)
headRequest.httpMethod = "HEAD"
session.dataTask(with: headRequest, completionHandler: { (data, response, error) in
if let error = error {
completion(nil, error)
return
}
guard let expectedContentLength = response?.expectedContentLength else {
completion(nil, FileCacheError.sizeNotAvailableForRemoteResource)
return
}
completion(expectedContentLength, nil)
}).resume()
}
/// Split the download request into multiple request to use more bandwidth
private func createDownloadParts() {
guard let size = contentLength else { return }
let numberOfRequests = 20
for i in 0..<numberOfRequests {
let start = Int64(ceil(CGFloat(Int64(i) * size) / CGFloat(numberOfRequests)))
let end = Int64(ceil(CGFloat(Int64(i + 1) * size) / CGFloat(numberOfRequests)))
parts.append(DownloadTask(for: url, from: start, to: end, in: session))
}
}
fileprivate func didFail(_ error: Error) {
cancel()
delegate?.didFail(self, error: error)
}
fileprivate func didFinishOnePart() {
if parts.filter({ $0.didWriteTo != nil }).count == parts.count {
mergeFiles()
}
}
/// Put together the download files
private func mergeFiles() {
let ext = self.url.pathExtension
let destination = Constants.tempDirectory
.appendingPathComponent("\(String.random(ofLength: 5))")
.appendingPathExtension(ext)
do {
let partLocations = parts.flatMap({ $0.didWriteTo })
try FileManager.default.merge(files: partLocations, to: destination)
delegate?.didFinish(self, didFinishDownloadingTo: destination)
for partLocation in partLocations {
do {
try FileManager.default.removeItem(at: partLocation)
} catch {
report(error)
}
}
} catch {
delegate?.didFail(self, error: error)
}
}
deinit {
FileDownloadManager.shared.tasks = FileDownloadManager.shared.tasks.filter({
$0.value !== self
})
}
}
protocol MultiPartDownloadTaskDelegate: class {
/// Called when the download progress changed
func didProgress(
_ downloadTask: MultiPartsDownloadTask
)
/// Called when the download finished succesfully
func didFinish(
_ downloadTask: MultiPartsDownloadTask,
didFinishDownloadingTo location: URL
)
/// Called when the download failed
func didFail(_ downloadTask: MultiPartsDownloadTask, error: Error)
}
/// Manage files downloads
class FileDownloadManager: NSObject {
static let shared = FileDownloadManager()
private var session: URLSession!
fileprivate var tasks = [Weak<MultiPartsDownloadTask>]()
private override init() {
super.init()
let config = URLSessionConfiguration.default
config.httpMaximumConnectionsPerHost = 50
session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
}
/// Create a task to download a file
func download(from url: URL) -> MultiPartsDownloadTask {
let task = MultiPartsDownloadTask(from: url, in: session)
tasks.append(Weak(value: task))
return task
}
/// Returns the download task that correspond to the URL task
fileprivate func match(request: URLSessionTask) -> (MultiPartsDownloadTask, DownloadTask)? {
for wtask in tasks {
if let task = wtask.value {
for part in task.parts {
if part.request == request {
return (task, part)
}
}
}
}
return nil
}
}
extension FileDownloadManager: URLSessionDownloadDelegate {
public func urlSession(
_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didWriteData bytesWritten: Int64,
totalBytesWritten: Int64,
totalBytesExpectedToWrite: Int64
) {
guard let x = match(request: downloadTask) else { return }
let multiPart = x.0
let part = x.1
part.bytesWritten = totalBytesWritten
multiPart.delegate?.didProgress(multiPart)
}
func urlSession(
_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didFinishDownloadingTo location: URL
) {
guard let x = match(request: downloadTask) else { return }
let multiPart = x.0
let part = x.1
let ext = multiPart.url.pathExtension
let destination = Constants.tempDirectory
.appendingPathComponent("\(String.random(ofLength: 5))")
.appendingPathExtension(ext)
do {
try FileManager.default.moveItem(at: location, to: destination)
} catch {
multiPart.didFail(error)
return
}
part.didWriteTo = destination
multiPart.didFinishOnePart()
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
guard let error = error, let multipart = match(request: task)?.0 else { return }
multipart.didFail(error)
}
}
extension FileManager {
/// Merge the files into one (without deleting the files)
func merge(files: [URL], to destination: URL, chunkSize: Int = 1000000) throws {
FileManager.default.createFile(atPath: destination.path, contents: nil, attributes: nil)
let writer = try FileHandle(forWritingTo: destination)
try files.forEach({ partLocation in
let reader = try FileHandle(forReadingFrom: partLocation)
var data = reader.readData(ofLength: chunkSize)
while data.count > 0 {
writer.write(data)
data = reader.readData(ofLength: chunkSize)
}
reader.closeFile()
})
writer.closeFile()
}
}
关于ios - URLSession 下载任务比互联网连接慢得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41547488/
自己试试看: import pandas as pd s=pd.Series(xrange(5000000)) %timeit s.loc[[0]] # You need pandas 0.15.1
我最近开始使用 Delphi 中的 DataSnap 来生成 RESTful Web 服务。在遵循 Marco Cantu 本人和互联网上其他几个人的指导后,我成功地使整个“链条”正常工作。 但是有一
我一直在为操作系统类(class)编写以下代码,但结果有些奇怪。该代码创建x线程并同时运行它们,以便将两个平方矩阵相乘。每个线程将输入矩阵的Number_of_rows/Number_of_threa
我正在尝试确定何时使用 parallel包以加快运行某些分析所需的时间。我需要做的一件事是创建矩阵,比较具有不同行数的两个数据框中的变量。我在 StackOverflow 上问了一个关于有效方法的问题
我最近对我的代码进行了一些清理,并在此过程中更改了此内容(不完全是真实的代码): read = act readSTRef test1 term i var = do t v^!terms.
我正在计时查询和同一个查询的执行时间,分页。 foreach (var x in productSource.OrderBy(p => p.AdminDisplayName) .Wher
我正在开发一个项目 (WPF),我有一个 Datagrid 从数据库加载超过 5000 条记录,所以我使用 BackgroundWorker 来通知用户数据正在加载,但它太慢了,我需要等待将近 2分钟
我在查询中添加 ORDER BY 时遇到问题。没有 ORDER BY 查询大约需要 26ms,一旦我添加 ORDER BY,它大约需要 20s。 我尝试了几种不同的方法,但似乎可以减少时间。 尝试 F
我是 Android 开发新手,遇到了性能问题。当我的 GridView 有太多项目时,它会变得有点慢。有什么方法可以让它运行得更快一些吗? 这是我使用的代码: 适配器: public class C
这里的要点是: 1.设置query_cache_type = 0;重置查询缓存; 2.在 heidisql(或任何其他客户端 UI)中运行任何查询 --> 执行,例如 45 毫秒 3.使用以下代码运行
想象下表: CREATE TABLE drops( id BIGSERIAL PRIMARY KEY, loc VARCHAR(5) NOT NULL, tag INT NOT
我的表 test_table 中的示例数据: date symbol value created_time 2010-01-09 symbol1
首先,如果已经有人问过这个问题,我深表歉意,至少我找不到任何东西。 无论如何,我将每 5 分钟运行一次 cron 任务。该脚本加载 79 个外部页面,而每个页面包含大约 200 个我需要在数据库中检查
我有下面的 SQL 代码,它来自 MySQL 数据库。现在它给了我期望的结果,但是查询很慢,我想我应该在进一步之前加快这个查询的速度。 表agentstatusinformation有: PKEY(主
我需要获取一个对象在 Core Data 中数千个其他对象之间的排名。现在,这是我的代码: - (void)rankMethod { //Fetch all objects NSFet
我正在编写一个应用程序,我需要在其中读取用户的地址簿并显示他所有联系人的列表。我正在测试的 iPhone 有大约 100 个联系人,加载联系人确实需要很多时间。 ABAddressBookRef ad
我正在使用 javascript 将 160 行添加到包含 10 列的表格中。如果我这样做: var cellText = document.createTextNode(value); cell.a
我是 Swift 的新手,我已经设置了一个 tableView,它从 JSON 提要中提取数据并将其加载到表中。 表格加载正常,但是当表格中有超过 10 个单元格时,它会变得缓慢且有些滞后,特别是它到
我在 InitializeCulture 和 Page_PreInit 事件之间的 asp.net 页面中遇到性能问题。当我重写 DeterminePostBackMode() 时,我发现问题出在 b
我在 Hetzner 上有一个带有 256GB RAM 6 个 CPU(12 个线程) 的专用服务器,它位于德国。我有 CENTOS 7.5。 EA4。 我的问题是 SSL。每天大约 2 小时,我们在
我是一名优秀的程序员,十分优秀!