I needed to traverse a large part (500k+ files) of the file tree, and switched from passing the FileManager.default.enumerator() a String to a URL. The traverse becomes 3x faster, and I am looking to understand why.
I'm testing on my Mac with an APFS formatted drive.
This is my test code to measure this in a Swift Playground:
import Cocoa
var startingTime: Date
var pathCount = 0
var urlCount = 0
let path = "/Users/tom/myfolder/"
let pathEnumerator = FileManager.default.enumerator(atPath: path)
let url = URL(fileURLWithPath: path)
let urlEnumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: nil)
print("== URL Enumerator ==")
startingTime = Date()
while let _ = urlEnumerator?.nextObject() as? URL {
urlCount += 1
}
print("\n\(urlCount) files.")
print("\(startingTime.timeIntervalSinceNow * -1) seconds elapsed")
print("\n\n")
print("== Path/String Enumerator ==")
startingTime = Date()
while let _ = pathEnumerator?.nextObject() as? String {
pathCount += 1
}
print("\n\(pathCount) files.")
print("\(startingTime.timeIntervalSinceNow * -1) seconds elapsed")
This is the output I get:
== URL Enumerator ==
541879 files.
40.580654978752136 seconds elapsed
== Path/String Enumerator ==
541879 files.
118.60869300365448 seconds elapsed
If I change the order (do the String version first), it makes no difference, so it doesn't appear to be a caching artefact.
Thanks to the suggestion from @Willeke, I ran this from Xcode's "Time Profiler" tool, and looked at the call stack for each path. It has highlighted a difference in behaviour between the two methods.
The call stack for the URL approach:

The call stack for the String approach:

My best interpretation of this is that the older String API is a recursive crawl of tree, which comes with lots of performance overheads, whereas the newer URL API has 'knows' the file tree and can just traverse it iteratively.
@Martin R suggested I check this in a compiled app (which is where the screenshots are from). The difference there is still 2x, but they were both a lot faster (11s vs 22s) than in the Playground.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With