307 lines
10 KiB
Swift
307 lines
10 KiB
Swift
//
|
|
// DynamicConcurrencyManager.swift
|
|
// MNNLLMiOS
|
|
//
|
|
// Created by 游薪渝(揽清) on 2025/8/27.
|
|
//
|
|
|
|
import Foundation
|
|
import Network
|
|
|
|
// MARK: - Dynamic Concurrency Configuration
|
|
|
|
/// Dynamic concurrency control manager - intelligently adjusts concurrency parameters
|
|
/// based on chunk count and network conditions
|
|
///
|
|
/// Usage Examples:
|
|
///
|
|
/// ```swift
|
|
/// // 1. Create dynamic concurrency manager
|
|
/// let concurrencyManager = DynamicConcurrencyManager()
|
|
///
|
|
/// // 2. Get download strategy for file
|
|
/// let fileSize: Int64 = 240 * 1024 * 1024 // 240MB
|
|
/// let strategy = await concurrencyManager.recommendDownloadStrategy(fileSize: fileSize)
|
|
///
|
|
/// print(strategy.description)
|
|
/// // Output might be:
|
|
/// // Download Strategy:
|
|
/// // - Use Chunking: Yes
|
|
/// // - Chunk Size: 10MB
|
|
/// // - Chunk Count: 24
|
|
/// // - Concurrency: 6 (24 chunks / 4 ideal chunks per concurrency = 6)
|
|
/// // - Network Type: wifi
|
|
/// // - Device Performance: high
|
|
///
|
|
/// // 3. Create DownloadConfig using strategy
|
|
/// let dynamicConfig = DownloadConfig(
|
|
/// maxConcurrentDownloads: strategy.concurrency,
|
|
/// chunkSize: strategy.chunkSize,
|
|
/// largeFileThreshold: strategy.chunkSize * 2,
|
|
/// maxRetries: 3,
|
|
/// retryDelay: 2.0
|
|
/// )
|
|
/// ```
|
|
///
|
|
/// Best Practices:
|
|
///
|
|
/// 1. **Intelligent Concurrency Control**:
|
|
/// - For 24 chunks: use 6-8 concurrent downloads (instead of fixed 3)
|
|
/// - For 4 chunks: use 2-3 concurrent downloads
|
|
/// - For 1 chunk: use 1 concurrent download
|
|
///
|
|
/// 2. **Network Adaptation**:
|
|
/// - WiFi: larger chunk size and more concurrency
|
|
/// - 4G: medium chunk size and concurrency
|
|
/// - 3G: small chunk size and less concurrency
|
|
///
|
|
/// 3. **Device Performance Consideration**:
|
|
/// - High-performance devices: can handle more concurrency
|
|
/// - Low-performance devices: reduce concurrency to avoid lag
|
|
///
|
|
/// 4. **Dynamic Adjustment**:
|
|
/// - Automatically adjust strategy when network status changes
|
|
/// - Dynamically optimize based on actual download performance
|
|
|
|
/// Configuration for dynamic concurrency management
|
|
///
|
|
/// This structure defines the parameters used to dynamically adjust download concurrency
|
|
/// based on network conditions and device performance characteristics.
|
|
///
|
|
/// - Parameters:
|
|
/// - baseConcurrency: The baseline number of concurrent downloads
|
|
/// - maxConcurrency: The maximum number of concurrent downloads allowed
|
|
/// - minConcurrency: The minimum number of concurrent downloads to maintain
|
|
/// - idealChunksPerConcurrency: The ideal number of chunks per concurrent download
|
|
/// - networkTypeMultiplier: Multiplier for network type adjustments
|
|
/// - devicePerformanceMultiplier: Multiplier for device performance adjustments
|
|
/// - largeFileThreshold: File size threshold for enabling chunked downloads
|
|
public struct DynamicConcurrencyConfig {
|
|
let baseConcurrency: Int
|
|
|
|
let maxConcurrency: Int
|
|
|
|
let minConcurrency: Int
|
|
|
|
let idealChunksPerConcurrency: Int
|
|
|
|
let networkTypeMultiplier: Double
|
|
|
|
let devicePerformanceMultiplier: Double
|
|
|
|
let largeFileThreshold: Int64
|
|
|
|
public static let `default` = DynamicConcurrencyConfig(
|
|
baseConcurrency: 3,
|
|
maxConcurrency: 8,
|
|
minConcurrency: 1,
|
|
idealChunksPerConcurrency: 3,
|
|
networkTypeMultiplier: 1.0,
|
|
devicePerformanceMultiplier: 1.0,
|
|
largeFileThreshold: 100 * 1024 * 1024
|
|
)
|
|
}
|
|
|
|
// MARK: - Network Type Detection
|
|
|
|
/// Network type classification for optimization
|
|
///
|
|
/// Categorizes different network connection types to enable appropriate
|
|
/// download strategy selection and performance optimization.
|
|
public enum NetworkType {
|
|
case wifi
|
|
case cellular
|
|
case lowBandwidth
|
|
case unknown
|
|
|
|
/// Multiplier for adjusting concurrency based on device performance
|
|
///
|
|
/// - Returns: A multiplier value used to scale the base concurrency level
|
|
var concurrencyMultiplier: Double {
|
|
switch self {
|
|
case .wifi: return 1.5
|
|
case .cellular: return 1.0
|
|
case .lowBandwidth: return 0.5
|
|
case .unknown: return 0.8
|
|
}
|
|
}
|
|
|
|
var recommendedChunkSize: Int64 {
|
|
switch self {
|
|
case .wifi: return 20 * 1024 * 1024 // 20MB
|
|
case .cellular: return 10 * 1024 * 1024 // 10MB
|
|
case .lowBandwidth: return 5 * 1024 * 1024 // 5MB
|
|
case .unknown: return 8 * 1024 * 1024 // 5MB
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Device Performance Detection
|
|
|
|
/// Device performance classification
|
|
///
|
|
/// Categorizes device performance capabilities to optimize download strategies
|
|
/// based on available processing power and memory resources.
|
|
public enum DevicePerformance {
|
|
case high
|
|
case medium
|
|
case low
|
|
|
|
var concurrencyMultiplier: Double {
|
|
switch self {
|
|
case .high: return 1.3
|
|
case .medium: return 1.0
|
|
case .low: return 0.7
|
|
}
|
|
}
|
|
|
|
/// Detect the current device's performance level
|
|
///
|
|
/// - Returns: The detected device performance classification
|
|
static func detect() -> DevicePerformance {
|
|
let processInfo = ProcessInfo.processInfo
|
|
let physicalMemory = processInfo.physicalMemory
|
|
let processorCount = processInfo.processorCount
|
|
|
|
// Determine device performance based on memory and processor count
|
|
if physicalMemory >= 6 * 1024 * 1024 * 1024 && processorCount >= 6 { // 6GB+ RAM, 6+ cores
|
|
return .high
|
|
} else if physicalMemory >= 3 * 1024 * 1024 * 1024 && processorCount >= 4 { // 3GB+ RAM, 4+ cores
|
|
return .medium
|
|
} else {
|
|
return .low
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Dynamic Concurrency Manager
|
|
|
|
@available(iOS 13.4, macOS 10.15, *)
|
|
public actor DynamicConcurrencyManager {
|
|
private let config: DynamicConcurrencyConfig
|
|
private let networkMonitor: NWPathMonitor
|
|
private var currentNetworkType: NetworkType = .unknown
|
|
private let devicePerformance: DevicePerformance
|
|
|
|
public init(config: DynamicConcurrencyConfig = .default) {
|
|
self.config = config
|
|
networkMonitor = NWPathMonitor()
|
|
devicePerformance = DevicePerformance.detect()
|
|
|
|
Task {
|
|
await startNetworkMonitoring()
|
|
}
|
|
}
|
|
|
|
private func startNetworkMonitoring() {
|
|
networkMonitor.pathUpdateHandler = { [weak self] path in
|
|
Task {
|
|
await self?.updateNetworkType(from: path)
|
|
}
|
|
}
|
|
|
|
let queue = DispatchQueue(label: "NetworkMonitor")
|
|
networkMonitor.start(queue: queue)
|
|
}
|
|
|
|
private func updateNetworkType(from path: NWPath) {
|
|
if path.usesInterfaceType(.wifi) {
|
|
currentNetworkType = .wifi
|
|
} else if path.usesInterfaceType(.cellular) {
|
|
currentNetworkType = .cellular
|
|
} else if path.status == .satisfied {
|
|
currentNetworkType = .unknown
|
|
} else {
|
|
currentNetworkType = .lowBandwidth
|
|
}
|
|
}
|
|
|
|
/// Calculate optimal concurrency based on chunk count and current network conditions
|
|
///
|
|
/// - Parameter chunkCount: The number of chunks to download
|
|
/// - Returns: The recommended number of concurrent downloads
|
|
public func calculateOptimalConcurrency(chunkCount: Int) -> Int {
|
|
// Base calculation: based on chunk count and ideal ratio
|
|
let baseConcurrency = max(1, min(chunkCount / config.idealChunksPerConcurrency, config.baseConcurrency))
|
|
|
|
// Apply network type weight
|
|
let networkAdjusted = Double(baseConcurrency) * currentNetworkType.concurrencyMultiplier
|
|
|
|
// Apply device performance weight
|
|
let performanceAdjusted = networkAdjusted * devicePerformance.concurrencyMultiplier
|
|
|
|
// Ensure within reasonable range
|
|
let finalConcurrency = Int(performanceAdjusted.rounded())
|
|
|
|
return max(config.minConcurrency, min(config.maxConcurrency, finalConcurrency))
|
|
}
|
|
|
|
/// Get current network status information
|
|
///
|
|
/// - Returns: A tuple containing the current network type and device performance
|
|
public func getNetworkInfo() -> (type: NetworkType, performance: DevicePerformance) {
|
|
return (currentNetworkType, devicePerformance)
|
|
}
|
|
|
|
/// Get recommended chunk size based on current network conditions and device performance
|
|
///
|
|
/// - Returns: The recommended chunk size in bytes
|
|
public func recommendedChunkSize() -> Int64 {
|
|
let baseChunkSize = currentNetworkType.recommendedChunkSize
|
|
let performanceMultiplier = devicePerformance.concurrencyMultiplier
|
|
|
|
return Int64(Double(baseChunkSize) * performanceMultiplier)
|
|
}
|
|
|
|
/// Recommend download strategy based on file size and network conditions
|
|
///
|
|
/// - Parameter fileSize: The size of the file being downloaded
|
|
/// - Returns: A complete download strategy configuration
|
|
public func recommendDownloadStrategy(fileSize: Int64) -> DownloadStrategy {
|
|
let chunkSize = recommendedChunkSize()
|
|
let shouldUseChunking = fileSize > config.largeFileThreshold
|
|
let chunkCount = shouldUseChunking ? Int(ceil(Double(fileSize) / Double(chunkSize))) : 1
|
|
let optimalConcurrency = calculateOptimalConcurrency(chunkCount: chunkCount)
|
|
|
|
return DownloadStrategy(
|
|
shouldUseChunking: shouldUseChunking,
|
|
chunkSize: chunkSize,
|
|
chunkCount: chunkCount,
|
|
concurrency: optimalConcurrency,
|
|
networkType: currentNetworkType,
|
|
devicePerformance: devicePerformance
|
|
)
|
|
}
|
|
|
|
deinit {
|
|
networkMonitor.cancel()
|
|
}
|
|
}
|
|
|
|
// MARK: - Download Strategy
|
|
|
|
/// Download strategy configuration
|
|
///
|
|
/// Contains all the parameters needed to optimize download performance
|
|
/// based on current network and device conditions.
|
|
public struct DownloadStrategy {
|
|
let shouldUseChunking: Bool
|
|
let chunkSize: Int64
|
|
let chunkCount: Int
|
|
let concurrency: Int
|
|
let networkType: NetworkType
|
|
let devicePerformance: DevicePerformance
|
|
|
|
var description: String {
|
|
return """
|
|
Download Strategy:
|
|
- Use Chunking: \(shouldUseChunking ? "Yes" : "No")
|
|
- Chunk Size: \(chunkSize / 1024 / 1024)MB
|
|
- Chunk Count: \(chunkCount)
|
|
- Concurrency: \(concurrency)
|
|
- Network Type: \(networkType)
|
|
- Device Performance: \(devicePerformance)
|
|
"""
|
|
}
|
|
}
|