1 //! An executor with task priorities.
2
3 use std::future::Future;
4 use std::thread;
5
6 use async_executor::{Executor, Task};
7 use futures_lite::{future, prelude::*};
8
9 /// Task priority.
10 #[repr(usize)]
11 #[derive(Debug, Clone, Copy)]
12 enum Priority {
13 High = 0,
14 Medium = 1,
15 Low = 2,
16 }
17
18 /// An executor with task priorities.
19 ///
20 /// Tasks with lower priorities only get polled when there are no tasks with higher priorities.
21 struct PriorityExecutor<'a> {
22 ex: [Executor<'a>; 3],
23 }
24
25 impl<'a> PriorityExecutor<'a> {
26 /// Creates a new executor.
new() -> PriorityExecutor<'a>27 const fn new() -> PriorityExecutor<'a> {
28 PriorityExecutor {
29 ex: [Executor::new(), Executor::new(), Executor::new()],
30 }
31 }
32
33 /// Spawns a task with the given priority.
spawn<T: Send + 'a>( &self, priority: Priority, future: impl Future<Output = T> + Send + 'a, ) -> Task<T>34 fn spawn<T: Send + 'a>(
35 &self,
36 priority: Priority,
37 future: impl Future<Output = T> + Send + 'a,
38 ) -> Task<T> {
39 self.ex[priority as usize].spawn(future)
40 }
41
42 /// Runs the executor forever.
run(&self)43 async fn run(&self) {
44 loop {
45 for _ in 0..200 {
46 let t0 = self.ex[0].tick();
47 let t1 = self.ex[1].tick();
48 let t2 = self.ex[2].tick();
49
50 // Wait until one of the ticks completes, trying them in order from highest
51 // priority to lowest priority.
52 t0.or(t1).or(t2).await;
53 }
54
55 // Yield every now and then.
56 future::yield_now().await;
57 }
58 }
59 }
60
main()61 fn main() {
62 static EX: PriorityExecutor<'_> = PriorityExecutor::new();
63
64 // Spawn a thread running the executor forever.
65 thread::spawn(|| future::block_on(EX.run()));
66
67 let mut tasks = Vec::new();
68
69 for _ in 0..20 {
70 // Choose a random priority.
71 let choice = [Priority::High, Priority::Medium, Priority::Low];
72 let priority = choice[fastrand::usize(..choice.len())];
73
74 // Spawn a task with this priority.
75 tasks.push(EX.spawn(priority, async move {
76 println!("{:?}", priority);
77 future::yield_now().await;
78 println!("{:?}", priority);
79 }));
80 }
81
82 for task in tasks {
83 future::block_on(task);
84 }
85 }
86