For RT you can write a scheduler that at any point knows if all processes will meet their deadlines and you can easily design an algorithm to get to the most efficient scheduling order.
In non-RT it gets harder because a process might not need to run at all and is just eternally paused on reading some dead socket, it might have higher priority than other processes, you might have 2000 processes to run but only 1000 timeslots left for the current timeslice.
A process might begin to eat up CPU time and you have to somehow preserve the interactivity of the system, ie prevent other processes from starving without starving the big process in turn.
And once you enter multi-CPU it gets even harder; coordinating multiple concurrent schedulers to run from the same task queue, which cannot ever take a simple spinlock without the system suddenly becoming dead.
The parent comment simply noted that setting up the timer interrupt is fairly easy (though if you want something precise and faster than 1ms and multicore it might get more complicated), it's the stuff after that were you are forced to solve NP-hard problems in a fast way.
I recommend the OSDev wiki for a deeper dive but ultimately, implementing processes involves a lot of different moving pieces that need to work.
The most basic process manager would be cooperative, otherwise you'd have to write drivers for some external driver to regularly drive an interrupt.
Cooperative means the program will either print A or B and then call an interrupt into the kernel. The kernel would save the registers and instruction pointer, restore the one of the other program (which prints the opposite of what the first printed; A or B) and do an interrupt return.
This doesn't scale beyond a few processes that you have written yourself very carefully.
Any more competent process management will need to rely on regular timer interrupts, will have to keep track of processes and how much CPU time they got, have a thread to run if nothing else can run, manage processes when they die and has to be able to switch in and out of ring3 for running the actual process. On top of that it has to be performant and efficient, you have only a few hundred opcodes before the latency of your process management becomes too large.