Subprocesses aren't used because the cost of forking is high. It's more efficient to fork a worker once, then have that worker keep doing work.
The problem now becomes transferring data to that worker, which is where celery comes into play.
Python threads cannot be used for CPU heavy loads because they all run on a single core.[0][1]
[0]: CPython threads are kernel threads but effectively act like user threads. All threads run within a single VM and thus restricted to a single core.
[1]: Jython does not have the same limitation.