Я играю в Swift 5.1 (на Ма c), проводя небольшие симуляции теннисных матчей. Естественно, часть моделирования случайным образом выбирает, кто выигрывает каждую точку.
Ниже приведена соответствующая часть кода, в которой я выполняю параллелизм.
func combine(result: MatchTally)
{
overallTally.add(result: result)
}
DispatchQueue.concurrentPerform(iterations: cycleCount){iterationNumber in
var counter = MatchTally()
for _ in 1...numberOfSimulations
{
let result = playMatch(between: playerOne, and: playerTwo)
counter[result.0, result.1] += 1
}
combiningQueue.sync {combine(result: counter)}
}
При выбранном соответствующем числе прогонов моделирования Одна очередь занимает около 5 секунд. Если я установил параллельные очереди равными 2, симуляция теперь занимает 3,8 с на очередь (т.е. потребовалось 7,2 с). Снова удвоение до 4 очередей приводит к 4,8 с / очередь. И, наконец, с 6 очередями (машина с 6-ядерным процессором Intel i7) все занимает 5,6 с / очередь.
Для тех, кому нужно больше убедить, что это связано с генерацией случайных чисел (я использую Double.random(0...1)
) Я заменил код, в котором большинство случайных результатов генерируется с фиксированным результатом (я не мог заменить второе место, поскольку мне все еще нужно было на ie -брейке), и скорректировал количество симуляций соответствующим образом, результаты были следующими:
- 1 очередь: 5 с / очередь
- 2 очереди: 2,7 с / очередь
- 4 очереди: 1,9 с / очередь
- 6 очередей: 1.7 с / очередь
Итак, как вы можете видеть, кажется, что случайная часть устойчива к параллельной работе.
Я также пробовал с drand48 () и столкнулся с те же проблемы. Кто-нибудь знает, так ли это на самом деле?
Xcode 11.3, Swift 5.1, macOS 10.15.3, Ma c mini 2018, 6-ядерный i7 (но в разные годы сталкивался с одним и тем же аппаратное обеспечение)
Для тех, кто заинтересован в том, чтобы воспроизвести это сами, вот код, который я создал и добавил к Александру.
import Foundation
func formatTime(_ date: Date) -> String
{
let df = DateFormatter()
df.dateFormat = "h:mm:ss.SSS"
return df.string(from: date)
}
func something(_ iteration: Int)
{
var tally = 0.0
let startTime = Date()
print("Start #\(iteration) - \(formatTime(startTime))")
for _ in 1...1_000_000
{
tally += Double.random(in: 0...100)
// tally += 3.5
}
let endTime = Date()
print("End #\(iteration) - \(formatTime(endTime)) - elapsed: \(endTime.timeIntervalSince(startTime))")
}
print("Single task performed on main thread")
something(0) // Used to get a baseline for single run
print("\nMultiple tasks performed concurrently")
DispatchQueue.concurrentPerform(iterations: 5, execute: something)
Замена случайной добавки в l oop для фиксированного один демонстрирует, насколько хорошо код масштабируется в одном сценарии, но не другой.