限られたコネクションリソースの中で、何を優先的にダウンロードするか?はユーザエクスペリエンス上重要になってくる場面も多いと思います。単純なfifo、lifoだけで制御できない要件の時に活用できそうな、priority項目の挙動について調査しました。
サマリ
- ドキュメント: [URLSessionTask] (https://developer.apple.com/reference/foundation/urlsessiontask)
- URLSessionTaskに設定するpriorityは全く考慮されない(無視されてる?)
- 優先度制御は自分で実装するしかない
- URLSessionのdelegateQueueはダウンロード順とは無関係(当たり前だけど)
実験したこと#1
placeimg.comでそこそこのサイズの画像を生成し、50個ダウンロードする。
25個はlowPriority、25個はhighPriority。
同時ダウンロード数はわかりやすいように1。
タスクの生成を終えてから一気にresume()。
コード
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
var config = URLSessionConfiguration.ephemeral
config.httpMaximumConnectionsPerHost = 1
let session = URLSession(configuration: config)
var tasks = [URLSessionTask]()
for i in 1...50 {
guard let url = URL(string: "http://placeimg.com/570/" + "90+i" + "/any") else {
print("failed: \(i)")
continue
}
let task = session.dataTask(with: url) { data, response, error in
print("finished: \(i <= 25 ? "low" : "high") \(i)")
}
task.priority = i <= 25 ? URLSessionTask.lowPriority : URLSessionTask.highPriority
tasks.append(task)
}
print("start resume")
tasks.forEach { $0.resume() }
print("end resume")
結果
priorityが考慮されず、resumeした順にダウンロードが開始されている模様。
本来であればpriorityが高い26-50のタスクが先に終わってほしいが、キレイに1-25が先に完了してしまっている。
start resume
end resume
finished: low 1
finished: low 2
finished: low 3
finished: low 4
finished: low 5
finished: low 6
finished: low 7
finished: low 8
finished: low 9
finished: low 10
finished: low 11
finished: low 12
finished: low 13
finished: low 14
finished: low 15
finished: low 16
finished: low 17
finished: low 18
finished: low 19
finished: low 20
finished: low 21
finished: low 22
finished: low 23
finished: low 24
finished: low 25
finished: high 26
finished: high 27
finished: high 28
finished: high 29
finished: high 30
finished: high 31
finished: high 32
finished: high 33
finished: high 34
finished: high 35
finished: high 36
finished: high 37
finished: high 38
finished: high 39
finished: high 40
finished: high 41
finished: high 42
finished: high 43
finished: high 44
finished: high 45
finished: high 46
finished: high 47
finished: high 48
finished: high 49
finished: high 50
実験したこと#2
URLSessionのイニシャライザに渡すOperationQueueのQoSを変更して確認。
コード
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
var config = URLSessionConfiguration.ephemeral
config.httpMaximumConnectionsPerHost = 1
var lowQueue = OperationQueue()
lowQueue.qualityOfService = .background
var highQueue = OperationQueue()
highQueue.qualityOfService = .userInteractive
let lowSession = URLSession(configuration: config, delegate: nil, delegateQueue: lowQueue)
let highSession = URLSession(configuration: config, delegate: nil, delegateQueue: highQueue)
var tasks = [URLSessionTask]()
for i in 1...50 {
guard let url = URL(string: "http://placeimg.com/570/" + "90+i" + "/any") else {
print("failed: \(i)")
continue
}
let task = (i <= 25 ? lowSession : highSession).dataTask(with: url) { data, response, error in
print("finished: \(i <= 25 ? "low" : "high") \(i)")
}
tasks.append(task)
}
print("start resume")
tasks.forEach { $0.resume() }
print("end resume")
結果
delegateQueueの設定はcompletionHandlerの実行優先度のはずなので、だめだとはおもったけどやはりだめでした。
start resume
end resume
finished: low 1
finished: low 2
finished: high 26
finished: low 3
finished: high 27
finished: low 4
finished: high 28
finished: low 5
finished: high 29
finished: low 6
finished: high 30
finished: low 7
finished: high 31
finished: low 8
finished: high 32
finished: low 9
finished: high 33
finished: low 10
finished: high 34
finished: low 11
finished: high 35
finished: low 12
finished: high 36
finished: low 13
finished: high 37
finished: low 14
finished: high 38
finished: low 15
finished: high 39
finished: high 40
finished: low 16
finished: low 17
finished: high 41
finished: low 18
finished: high 42
finished: low 19
finished: high 43
finished: low 20
finished: high 44
finished: low 21
finished: high 45
finished: low 22
finished: high 46
finished: low 23
finished: high 47
finished: low 24
finished: high 48
finished: low 25
finished: high 49
finished: high 50
どういうこと?
おそらくpriorityはただのプロパティで、次のtaskをresumeするときに自分で見て決めてねってことだと思います。