Files
MarkBase Admin 8a66b9086a
CI / build (push) Waiting to run
CI / unit-tests (push) Blocked by required conditions
CI / lint (push) Blocked by required conditions
v2: Initial clean branch with unit tests + CI/CD pipeline
- Started from ac75faa (initial E4B-MarkBase integration)
- Kept Sources/ (all engine code) + Package.swift + .gitignore
- Removed all ad-hoc tests, documentation, scripts, Python files
- Added Tests/00_Unit/ (MathTest, TokenizerTest, SamplerTest)
- Added .gitea/workflows/ci.yaml (build + unit tests + lint)
- Added Scripts/check_resources.sh (memory-aware test runner)
- Added Tests/Manifest.json (resource requirements for all tests)
- Focus: 4-bit quantized models only
2026-07-05 13:29:25 +08:00

107 lines
3.4 KiB
Swift

import Foundation
import os
// ─────────────────────────────────────────────────────────────
// Concurrent Request Handling with Dynamic Concurrency
// ─────────────────────────────────────────────────────────────
/// Request queue for concurrent processing with dynamic concurrency
public actor RequestQueue {
private let controller: DynamicConcurrencyController
private var semaphore: AsyncSemaphore
public init(controller: DynamicConcurrencyController) {
self.controller = controller
self.semaphore = AsyncSemaphore(value: 4)
}
public func initialize() async {
let maxConcurrency = await controller.getCurrentMax()
semaphore = AsyncSemaphore(value: maxConcurrency)
}
/// Execute request with concurrency limit
public func execute<T: Sendable>(_ operation: @escaping @Sendable () async throws -> T) async throws -> T {
await semaphore.wait()
defer { semaphore.signal() }
return try await operation()
}
/// Update semaphore when concurrency changes
public func updateSemaphore(newMax: Int) {
semaphore = AsyncSemaphore(value: newMax)
}
}
/// Async semaphore for concurrency control
public final class AsyncSemaphore: @unchecked Sendable {
private var value: Int
private let lock = OSAllocatedUnfairLock()
private var waiters: [CheckedContinuation<Void, Never>] = []
public init(value: Int) {
self.value = value
}
public func wait() async {
let shouldWait = lock.withLock {
if value > 0 {
value -= 1
return false
}
return true
}
guard shouldWait else { return }
return await withCheckedContinuation { continuation in
lock.withLock {
waiters.append(continuation)
}
}
}
public func signal() {
lock.withLock {
if !waiters.isEmpty {
let waiter = waiters.removeFirst()
waiter.resume()
} else {
value += 1
}
}
}
}
/// Batch request processor with dynamic concurrency
public actor BatchProcessor {
private let requestQueue: RequestQueue
public init(controller: DynamicConcurrencyController) {
self.requestQueue = RequestQueue(controller: controller)
}
/// Process multiple requests concurrently
public func processBatch<T: Sendable>(
_ requests: [@Sendable () async throws -> T]
) async throws -> [T] {
try await withThrowingTaskGroup(of: (Int, T).self) { group in
var results: [T?] = Array(repeating: nil, count: requests.count)
for (index, request) in requests.enumerated() {
let req = request
group.addTask {
let result = try await self.requestQueue.execute(req)
return (index, result)
}
}
for try await (index, result) in group {
results[index] = result
}
return results.compactMap { $0 }
}
}
}