swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
66.85k stars 10.3k forks source link

`Task.yield()` and `Task.sleep()` do not respect task executor preference #74395

Open stephencelis opened 3 weeks ago

stephencelis commented 3 weeks ago

Description

From this discussion: https://forums.swift.org/t/task-executor-preference-and-deterministic-scheduling/72448

Reproduction

final class MainExecutor: TaskExecutor {
  func enqueue(_ job: consuming ExecutorJob) {
    job.runSynchronously(
      isolatedTo: MainActor.sharedUnownedExecutor,
      taskExecutor: asUnownedTaskExecutor()
    )
  }
}

func testSerializedExecution_YieldEveryOtherValue() async {
  let xs = Mutex<[Int]>([])
  await withTaskExecutorPreference(MainExecutor()) {
    await withTaskGroup(of: Void.self) { group in
      for x in 1...1000 {
        group.addTask {
          if x.isMultiple(of: 2) { await Task.yield() }
          xs.withLock { $0.append(x) }
        }
      }
    }
  }
  XCTAssertEqual(
   (0...499).map { $0 * 2 + 1 } + (1...500).map { $0 * 2 },
    xs.withLock { $0 }
  )
}

Expected behavior

I expect the test to pass.

Environment

swift-driver version: 1.109.2 Apple Swift version 6.0 (swiftlang-6.0.0.3.300 clang-1600.0.20.10) Target: arm64-apple-macosx14.0

Additional information

No response

stephencelis commented 3 weeks ago

/cc @FranzBusch @ktoso

ktoso commented 3 weeks ago

Thanks for the report! This is tracked internally as rdar://126047740

ktoso commented 2 weeks ago

We're tracking this as rdar://126047740