or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

channels.mdcoroutine-builders.mdcoroutine-management.mddispatchers.mderror-handling.mdflow-api.mdindex.mdselect-expression.mdsynchronization.md

dispatchers.mddocs/

0

# Dispatchers

1

2

Execution context control for coroutines including standard dispatchers and custom dispatcher creation. Dispatchers determine which thread or thread pool coroutines execute on.

3

4

## Capabilities

5

6

### CoroutineDispatcher Base Class

7

8

Abstract base class for all coroutine dispatchers.

9

10

```kotlin { .api }

11

/**

12

* Base class for coroutine dispatchers

13

*/

14

abstract class CoroutineDispatcher : ContinuationInterceptor {

15

/** Dispatch the coroutine to appropriate thread/context */

16

abstract fun dispatch(context: CoroutineContext, block: Runnable)

17

18

/** Check if dispatch is needed for the current context */

19

open fun isDispatchNeeded(context: CoroutineContext): Boolean = true

20

21

/** Create a dispatcher with limited parallelism */

22

open fun limitedParallelism(parallelism: Int): CoroutineDispatcher

23

24

/** Operator overload for withContext-like behavior */

25

suspend operator fun <T> invoke(block: suspend CoroutineScope.() -> T): T

26

}

27

```

28

29

### Standard Dispatchers

30

31

Built-in dispatchers for common execution contexts.

32

33

```kotlin { .api }

34

/**

35

* Contains standard coroutine dispatchers

36

*/

37

object Dispatchers {

38

/** Optimized for CPU-intensive work */

39

val Default: CoroutineDispatcher

40

41

/** For UI operations (platform-specific) */

42

val Main: MainCoroutineDispatcher

43

44

/** For blocking I/O operations */

45

val IO: CoroutineDispatcher

46

47

/** Not confined to any specific thread */

48

val Unconfined: CoroutineDispatcher

49

}

50

```

51

52

**Usage Examples:**

53

54

```kotlin

55

import kotlinx.coroutines.*

56

57

// CPU-intensive work

58

val result = withContext(Dispatchers.Default) {

59

heavyComputation()

60

}

61

62

// I/O operations

63

val data = withContext(Dispatchers.IO) {

64

readFile("data.txt")

65

}

66

67

// UI updates (Android/Desktop)

68

withContext(Dispatchers.Main) {

69

updateUI(result)

70

}

71

72

// Unconfined execution

73

launch(Dispatchers.Unconfined) {

74

// Runs in caller thread until first suspension

75

println("Start: ${Thread.currentThread().name}")

76

delay(100)

77

println("After delay: ${Thread.currentThread().name}")

78

}

79

```

80

81

### Main Dispatcher

82

83

Specialized dispatcher for UI thread operations.

84

85

```kotlin { .api }

86

/**

87

* Dispatcher for UI operations

88

*/

89

abstract class MainCoroutineDispatcher : CoroutineDispatcher() {

90

/** Immediate execution if already on main thread */

91

abstract val immediate: MainCoroutineDispatcher

92

93

/** Factory for creating main dispatcher */

94

companion object {

95

fun createDispatcher(): MainCoroutineDispatcher

96

}

97

}

98

```

99

100

**Usage Examples:**

101

102

```kotlin

103

// Regular main dispatcher

104

withContext(Dispatchers.Main) {

105

updateUI() // May dispatch even if already on main thread

106

}

107

108

// Immediate main dispatcher

109

withContext(Dispatchers.Main.immediate) {

110

updateUI() // No dispatch if already on main thread

111

}

112

```

113

114

### Custom Dispatchers

115

116

Creating custom dispatchers from executors and thread pools.

117

118

```kotlin { .api }

119

/**

120

* Executor-based dispatcher

121

*/

122

abstract class ExecutorCoroutineDispatcher : CoroutineDispatcher(), Closeable {

123

/** The underlying executor */

124

abstract val executor: Executor

125

126

/** Close the dispatcher and shutdown executor */

127

abstract override fun close()

128

}

129

130

/**

131

* Convert Executor to CoroutineDispatcher

132

*/

133

fun Executor.asCoroutineDispatcher(): ExecutorCoroutineDispatcher

134

135

/**

136

* Convert ExecutorService to CoroutineDispatcher

137

*/

138

fun ExecutorService.asCoroutineDispatcher(): ExecutorCoroutineDispatcher

139

140

/**

141

* Convert CoroutineDispatcher to Executor

142

*/

143

fun CoroutineDispatcher.asExecutor(): Executor

144

145

/**

146

* Create single-threaded dispatcher

147

*/

148

fun newSingleThreadContext(name: String): ExecutorCoroutineDispatcher

149

150

/**

151

* Create fixed thread pool dispatcher

152

*/

153

fun newFixedThreadPoolContext(nThreads: Int, name: String): ExecutorCoroutineDispatcher

154

```

155

156

**Usage Examples:**

157

158

```kotlin

159

import kotlinx.coroutines.*

160

import java.util.concurrent.*

161

162

// Custom thread pool

163

val customDispatcher = Executors.newFixedThreadPool(4).asCoroutineDispatcher()

164

165

// Use custom dispatcher

166

val result = withContext(customDispatcher) {

167

performWork()

168

}

169

170

// Always close custom dispatchers

171

customDispatcher.close()

172

173

// Single thread dispatcher

174

val singleThreadDispatcher = newSingleThreadContext("MyThread")

175

try {

176

launch(singleThreadDispatcher) {

177

// Runs on dedicated thread "MyThread"

178

serialProcessing()

179

}

180

} finally {

181

singleThreadDispatcher.close()

182

}

183

```

184

185

## Dispatcher Characteristics

186

187

### Dispatchers.Default

188

189

- **Purpose**: CPU-intensive computations

190

- **Thread Pool**: Shared pool sized to number of CPU cores

191

- **Use Cases**: Mathematical calculations, data processing, algorithms

192

- **Avoid**: Blocking I/O operations

193

194

```kotlin

195

// Good use of Default

196

val primes = withContext(Dispatchers.Default) {

197

findPrimesInRange(1..1000000)

198

}

199

200

// Bad use of Default - blocks threads

201

withContext(Dispatchers.Default) {

202

Thread.sleep(1000) // Don't do this!

203

}

204

```

205

206

### Dispatchers.IO

207

208

- **Purpose**: Blocking I/O operations

209

- **Thread Pool**: Larger pool that can grow as needed

210

- **Use Cases**: File operations, network calls, database access

211

- **Design**: Can handle thread blocking without starving other coroutines

212

213

```kotlin

214

// File I/O

215

val content = withContext(Dispatchers.IO) {

216

File("large-file.txt").readText()

217

}

218

219

// Network calls

220

val response = withContext(Dispatchers.IO) {

221

httpClient.get("https://api.example.com/data")

222

}

223

224

// Database operations

225

val users = withContext(Dispatchers.IO) {

226

database.query("SELECT * FROM users")

227

}

228

```

229

230

### Dispatchers.Main

231

232

- **Purpose**: UI thread operations

233

- **Thread**: Single UI thread (platform-specific)

234

- **Use Cases**: UI updates, view modifications

235

- **Platform**: Android, Swing, JavaFX, etc.

236

237

```kotlin

238

// UI updates

239

withContext(Dispatchers.Main) {

240

progressBar.progress = 100

241

statusLabel.text = "Complete"

242

}

243

```

244

245

### Dispatchers.Unconfined

246

247

- **Purpose**: Special dispatcher that doesn't confine execution

248

- **Behavior**: Starts in caller thread, resumes in whatever thread the suspended function uses

249

- **Use Cases**: Testing, specific performance scenarios

250

- **Caution**: Can lead to unpredictable thread switching

251

252

```kotlin

253

launch(Dispatchers.Unconfined) {

254

println("1: ${Thread.currentThread().name}")

255

delay(100) // May resume on different thread

256

println("2: ${Thread.currentThread().name}")

257

}

258

```

259

260

## Best Practices

261

262

### Choose Appropriate Dispatcher

263

264

```kotlin

265

// CPU work

266

val computed = withContext(Dispatchers.Default) {

267

expensiveCalculation()

268

}

269

270

// I/O work

271

val data = withContext(Dispatchers.IO) {

272

loadFromDatabase()

273

}

274

275

// UI updates

276

withContext(Dispatchers.Main) {

277

displayResult(computed, data)

278

}

279

```

280

281

### Avoid Unnecessary Context Switches

282

283

```kotlin

284

// Inefficient - multiple context switches

285

suspend fun processData() {

286

val data1 = withContext(Dispatchers.IO) { loadData1() }

287

val data2 = withContext(Dispatchers.IO) { loadData2() }

288

val data3 = withContext(Dispatchers.IO) { loadData3() }

289

}

290

291

// Better - single context switch

292

suspend fun processDataEfficient() {

293

withContext(Dispatchers.IO) {

294

val data1 = loadData1()

295

val data2 = loadData2()

296

val data3 = loadData3()

297

}

298

}

299

```

300

301

### Resource Management

302

303

```kotlin

304

// Always close custom dispatchers

305

val customDispatcher = newFixedThreadPoolContext(4, "Custom")

306

try {

307

// Use dispatcher

308

withContext(customDispatcher) {

309

performWork()

310

}

311

} finally {

312

customDispatcher.close()

313

}

314

315

// Or use 'use' extension

316

newSingleThreadContext("Worker").use { dispatcher ->

317

withContext(dispatcher) {

318

performWork()

319

}

320

} // Automatically closed

321

```

322

323

## JVM Integration

324

325

### CompletableFuture Integration

326

327

Coroutines can interoperate seamlessly with Java's CompletableFuture.

328

329

```kotlin { .api }

330

/**

331

* Start coroutine and return CompletableFuture

332

*/

333

fun <T> CoroutineScope.future(

334

context: CoroutineContext = EmptyCoroutineContext,

335

start: CoroutineStart = CoroutineStart.DEFAULT,

336

block: suspend CoroutineScope.() -> T

337

): CompletableFuture<T>

338

339

/**

340

* Convert Deferred to CompletableFuture

341

*/

342

fun <T> Deferred<T>.asCompletableFuture(): CompletableFuture<T>

343

344

/**

345

* Await CompletableFuture completion

346

*/

347

suspend fun <T> CompletableFuture<T>.await(): T

348

```

349

350

**Usage Examples:**

351

352

```kotlin

353

import kotlinx.coroutines.*

354

import java.util.concurrent.CompletableFuture

355

356

// Create CompletableFuture from coroutine

357

val future: CompletableFuture<String> = GlobalScope.future {

358

delay(100)

359

"Hello from coroutine"

360

}

361

362

// Use traditional CompletableFuture API

363

future.thenAccept { result ->

364

println(result)

365

}

366

367

// Await Java CompletableFuture in coroutine

368

suspend fun processJavaFuture() {

369

val javaFuture: CompletableFuture<String> = CompletableFuture.supplyAsync {

370

Thread.sleep(100)

371

"Hello from Java"

372

}

373

374

val result = javaFuture.await()

375

println(result)

376

}

377

378

// Convert Deferred to CompletableFuture

379

val deferred = async { computeValue() }

380

val future = deferred.asCompletableFuture()

381

```

382

383

### Thread Context Propagation

384

385

Support for propagating thread-local variables across coroutine boundaries.

386

387

```kotlin { .api }

388

/**

389

* Element for propagating thread-local data

390

*/

391

interface ThreadContextElement<S> : CoroutineContext.Element {

392

/** Update thread-local state and return previous state */

393

fun updateThreadContext(context: CoroutineContext): S

394

/** Restore previous thread-local state */

395

fun restoreThreadContext(context: CoroutineContext, oldState: S)

396

}

397

```