There are several different concepts related to the field of parallel computing.
- Parallel execution
- Asynchronous execution
Each of these terms is strictly defined and has a clear meaning.
Concurrency (*) is the most general term that says that more than one task is running at the same time. For example, you can watch TV and comment on photos on Facebook at the same time. Windows, even the 95th could (**) simultaneously play music and show pictures.
Concurrent execution is the most general term, which does not say how this concurrency will be obtained: by suspending some computational elements and switching them to another task, by truly concurrent execution, by delegating work to other devices, or otherwise. It does not matter.
Competitive performance means that more than one task will be solved within a certain period of time.
Parallel computing means having more than one computing device (for example, a processor) that will simultaneously perform several tasks.
Concurrent execution is a strict subset of concurrent execution. This means that parallel programming is impossible on a computer with one processor;)
Multithreading is one way to implement concurrent execution by separating out the worker thread abstraction.
Threads abstract low-level details from the user and allow more than one work to be done in parallel. The operating system, runtime, or library hides the details of whether multithreading will be concurrent (when there are more threads than physical processors) or parallel (when the number of threads is less than or equal to the number of processors and multiple tasks are physically executing simultaneously).
Asynchrony means that an operation can be performed by someone on the side: a remote Web site, server, or other device outside of the current computing device.
The main property of such operations is that the beginning of such an operation requires much less time than the main work. This allows many asynchronous operations to be performed simultaneously, even on a device with a small number of computing devices.
CPU-bound and IO-Bound operations
Another important point from the developer's point of view is the difference between CPU-bound and IO-bound operations. CPU-Bound operations load the computing power of the current device, and IO-Bound allows you to perform a task outside the current piece of hardware.
The difference is important because the number of simultaneous operations depends on which category they belong to. It is quite normal to run hundreds of IO-Bound operations in parallel, and hope that there are enough resources to process all the results. To run in parallel too many CPU-bound operations (more than the number of computing devices) is pointless.
Returning to the original question: it makes no sense to execute the Calc method in 1000 threads if it is CPU-Intensive (loads the central processor), since this will lead to a drop in the overall efficiency of calculations. The OS will have to switch several available cores to serve hundreds of threads. And this process is not cheap.
The simplest and most effective way to solve a CPU-Intensive task is to use the Fork-Join idiom: a task (for example, input data) needs to be split into a certain number of subtasks that can be performed in parallel. Each subtask should be independent and not access shared variables / memory. Then, you need to collect intermediate results and combine them