Don’t call yourself unlucky if you haven’t tried hard. It is said that like + favorites == learn
In addition to coroutines, you will learn about processes, threads, concurrency…
process
define
Process is a running activity of a program on a data set in a computer. It is the basic unit of resource allocation and scheduling in the system and the basis of operating system structure. In the early process-oriented computer architecture, the process is the basic execution entity of the program. In modern thread-oriented computer architectures, processes are containers for threads. A program is a description of instructions, data and their organizational form, while a process is an entity of the program.
- Narrow definition: a process is the execution of a program such as an app that is launched.
- Broad definition: a process is an independent function of the program about a data set of a running activity. It is a
The basic unit of dynamic execution of an operating system
In traditional operating systems, processes are both the basic unit of allocation and execution.
1. Resource management unit (OS) with the smallest process 2. A startup instance of an application. The process has code and open file resources, data resources, and separate memory spaceCopy the code
The life cycle of a process is basically controlled by the operating system kernel, that is, the creation, switchover, destruction and other operations of a process will be trapped in the kernel for system calls. This operation consumes a lot of energy. When process destruction is carried out, including but not only the memory address space, kernel-state stack and hardware context (CPU register) switch, even in the case of less memory resources, the data stored in memory will be written to the disk swap area, which costs a lot. Therefore, we can see that the more processes the system runs, the more sluggish the system becomes.
Characteristics of the
- Each process has its own address space, typically containing text areas, data areas, and stacks
- A process is a program in execution. The program is an inanimate entity. Only when the processor gives the program life, it can become an active entity, which is called a process
- The process itself does not run and is a container for threads. Threads cannot execute alone and must form processes
- A program has at least one process, and a process has at least one thread
- For an operating system, a task is a process, for example, opening a browser is starting a browser process. To open an app is to open a process.
- Some processes do more than one thing at a time. Within a process, you can do multiple things at the same time. For example, you can watch a video and send a barrage.
Process status :(three states)
- Ready: Fetch all resources outside the CPU, as soon as the processor allocates resources
- Run: The program begins execution after obtaining the resources allocated by the processor
- Blocking: When a program condition is insufficient, execution must wait for the commit to be fulfilled.
State,
- Creation state: The process needs to apply for a blank PCB when it is created, and fill in the control and management process information.
Complete resource allocation
. If the creation work cannot be completed, for example, the resources cannot be met, the process cannot be scheduled to run. The state is called the creation state - Ready: The process is ready,
The required resources are allocated and run as soon as they are allocated to the CPU
- Execution status: process
In the ready state After a process is scheduled, it enters the execution state
- Blocked: The running process is temporarily unable to run due to some event (I/O request, failed to apply for cache).
The process is blocked
. Enters a ready state waiting for a system call when the request is satisfied - Termination status:
The process ended, or an error occurred, or was terminated by the system
To enter the termination state. Unenforceable
thread
define
A Thread is the smallest unit in which an operating system can schedule operations. It is contained within the process and is the actual operating unit within the process. A thread is a single sequential flow of control in a process, and multiple threads can be concurrent in a process, each performing a different task in parallel. In Unix System V and SunOS, they are also referred to as Lightweight processes, but more commonly referred to as kernel threads, while user threads are referred to as threads.
1. The smallest execution unit of threads [operating system] 2. A process contains multiple threads (one master and many slaves) and has its own stack spaceCopy the code
Characteristics of the
- There is at least one thread in a process, otherwise there is no point in existence
- Within a process, to do more than one thing at a time, we need to run multiple sub-tasks at the same time, we call these sub-tasks within the process threads
- Multithreading is for the simultaneous completion of multiple tasks (running multiple threads in a single program at the same time to complete different tasks and work), is to improve the efficiency of resource use to improve the efficiency of the system, rather than to improve the efficiency of operation.
- A simple analogy, multithreading is like car maintenance workers have car wash workers have repair and beauty, and the process is to be cleaned and maintained beauty shop car
- A thread is the smallest unit of a program’s execution flow. A standard thread consists of the current thread ID, current instruction pointer, registers, and stack
- Multiple threads in the same process can execute concurrently
Thread status:
- Ready: a thread that has all the conditions to run, is logically ready to run, and is waiting on the processor
- Running: indicates that the thread – occupied processor is running
- Blocked: A thread is waiting for an event that cannot be logically executed
Process versus thread
-
Processes are the basic unit of operating system resource allocation, while threads are the basic unit of task scheduling and execution
The implementation of threads and processes varies from operating system to operating system, but in most cases a thread is a component of a process. Processes are the basic unit of operating system resource allocation, while threads are the basic unit of task scheduling and execution. In the operating system can run multiple processes at the same time; Multiple threads execute simultaneously in the same process (with CPU scheduling, only one thread executes in each timeslice).
-
A process has a separate memory space, and threads share the memory space in their own process
A process is an independent entity in the system, which can have its own independent resources. The system allocates different memory space for each process during running, so each process has its own private memory space. A user’s process cannot directly access the memory space of another process without permission from the process itself. In the case of threads, the system allocates no memory (the resources used by threads come from the resources of the process they belong to), and only the resources of the process can be shared between multiple threads in a process. Different processes do not share these resources.
-
Switching between processes is more expensive and switching between threads is less expensive
Each process has its own data space (program context), and switching between processes is expensive. Thread can be regarded as a lightweight process, the same kind of thread sharing code and data space, each thread has its own independent running stack and program counter (PC), the switching consumption of thread is slightly less than the process, less memory and disk exchange, but still there will be stack mapping and switching.
-
A program is a collection of static instructions, while a process is a collection of instructions that are active in the system
The difference between a process and a program is that a program is just a static set of instructions, while a process is a set of instructions that is active in the system. The concept of time has been added to the process. The concept of a process having its own life cycle and various states is not available in a program.
coroutines
define
Coroutines, also known as microthreads, fibers. English name Coroutine. A coroutine is a lightweight thread in user mode whose scheduling is completely controlled by the user (both processes and threads are scheduled by the CPU kernel).
1. Coroutines special functions [program control] 2. A thread can have more than one coroutine 3. Execution can be paused (the expression for paused is called pause point) 4. 5. Event loops are the underlying building blocks of asynchronous programmingCopy the code
As the name suggests, coroutines are smaller in granularity than threads and are user-managed and controlled. Multiple coroutines can run on a single thread. So what is the background of coroutines? Let’s take a look at some of the features that affect performance in threads today:
- Use locking mechanism
- Context switching between threads
- Switching between running and blocking states of a thread
Any of these points can be CPU intensive. Relatively speaking, the coroutine is controlled by the program itself, there is no overhead of thread switching, and there is no need for locking mechanism, because running in the same thread, there is no conflict of variables written at the same time, the operation of shared resources in the coroutine is not locked, only need to judge the state, so the execution efficiency is much higher than the thread.
Characteristics of the
Coroutines have their own register context and stack. When the coroutine schedules the switch, the register context and stack are saved in other places, and when the switch is cut back, the previously saved register context and stack are restored. The direct operation of the stack basically has no kernel switching overhead, and you can access global variables without locking, so the context switch is very fast. Thus: the coroutine can retain the state of the last call (that is, a specific combination of all local states), and each procedure reentry is equivalent to entering the state of the last call, or in other words, the position of the logical flow from which it left the last time.
-
For coroutines (user-level threads), which is transparent to the kernel, namely system does not know of the existence of coroutines, is entirely their own by the user program schedule, because is controlled by the user program itself, so it is difficult to do the compulsory CPU like preemptive scheduling control switch to the other process/thread, usually only for collaborative scheduling, Other coroutines can be executed only after they voluntarily transfer control.
-
For processes and threads, there is a kernel for scheduling, the concept of CPU time slice, preemptive scheduling (there are multiple scheduling algorithms)
Advantages of coroutines:
- Without the overhead of thread context switching, goroutine switch scheduling overhead is much lower than that of threads.
- There is no overhead of atomic operation locking and synchronization
- Easy to switch control flow, simplify the programming model
- By default, each Goroutine takes up far less memory than a Java or C thread. Goroutine: 2KB (official), Thread: 8MB (refer to network)
High concurrency + high scalability + low cost: a CPU can support tens of thousands of coroutines. So it’s good for high-concurrency processing.
Disadvantages of coroutines:
- Unable to utilize multi-core resources: Coroutines are single-threaded by nature and cannot use multiple cores on a single CPU at the same time. Coroutines need to work with processes to run on multiple cpus. Of course, most of the applications we write on a daily basis don’t need this, unless they are CPU intensive.
- A Blocking operation (such as IO) blocks the entire program
Cpu-intensive code (various loops, calculations, and so on) : Use multiple processes. IO intensive code (file processing, web crawlers, etc.) : Use multithreading
Concurrency and parallelism
concurrent
Concurrency: In an operating system, several programs are running on the same CPU at any one time, but only one program is running on the CPU at any one time.
When there are multiple threads, if the system has only one CPU, then the CPU can not really run multiple threads at the same time, the CPU running time will be divided into several periods, each time period is allocated to each thread to execute, a period of time when one thread is running, other threads are suspended, this is concurrency. Concurrency solves the problem of programs queuing up, and if one program blocks, the others can still execute.
parallel
Parallel: When the OPERATING system has multiple cpus, one CPU processes thread A and the other CPU processes thread B. The two threads do not seize CPU resources from each other and can be processed simultaneously. This mode is called parallel.
The difference between concurrency and parallelism
- Concurrency only gives the impression that multiple programs are running at the same time on a macro level, but in a real single-CPU system, only one program is running at any one time, and on a micro level, these programs are executed alternately on a time-sharing basis.
- In a multi-CPU system, these concurrent programs can be distributed to different cpus for processing, each CPU for processing one program, so that multiple programs can be executed simultaneously.
Highly praised examples on Zhihu:
- You’re in the middle of a meal when the phone comes and you don’t answer it until after you’ve finished, which means you don’t support concurrency or parallelism.
- You’re in the middle of a meal when the phone call comes, you stop to answer the phone, and then continue eating, which means you support concurrency.
- You’re in the middle of a meal when the phone call comes and you’re eating while you’re talking, which means you support parallelism.
The key to concurrency is that you have the ability to handle multiple tasks, not necessarily all at once. The key to parallelism is your ability to handle multiple tasks at once. So I think the most important thing is whether they are “simultaneously.”
Coroutines in JavaScript
Development of JavaScript coroutines
- Synchronization code
- Asynchronous JavaScript: Callback Hell
- ES6 introduces Promise/ A +, generator Generators(syntaxfunction foo(){}* Functions can be given the ability to pause execution/save context/resume execution state), and the new keyword yield pauses generator functions.
- ES7 introduces async function /await candy. Async can declare an asynchronous function (a Generator and an automatic executor wrapped in a function) that returns a Promise object. Await can wait for a Promise object resolve and get the result,
The callback function is also used in Promise. A callback function is passed in both the then and catch methods to execute when a Promise is fulfilled and rejected, respectively, so that it can be linked together to complete a series of tasks. Then ().then()… To make code writing and reading more intuitive
The underlying implementation mechanism for the Generator is the Coroutine.
function* foo() {
console.log("foo start")
a = yield 1;
console.log("foo a", a)
yield 2;
yield 3;
console.log("foo end")}const gen = foo();
console.log(gen.next().value); / / 1
/ / gen. Send (" a ") / / http://www.voidcn.com/article/p-syzbwqht-bvv.html SpiderMonkey engine supports the send syntax
console.log(gen.next().value); / / 2
console.log(gen.next().value); / / 3
console.log(foo().next().value); / / 1
console.log(foo().next().value); / / 1
/*
foo start
1
foo a undefined
2
3
foo start
1
foo start
1
*/
Copy the code
JavaScript coroutine maturity
Promise to continue
A Promise is essentially a state machine that represents the final completion (or failure) of an asynchronous operation and its resulting value. It has three states:
- Pending: The initial state, which is neither successful nor failed.
- This is a pity: which means that the operation will be completed successfully.
- Rejected: Indicates that the operation fails.
Eventually, a Promise will have two states, one successful and one failed. When pending changes, the Promise object will call different handlers based on the final state.
Async, await syntax sugar
Async and await are packages of Generator and Promise combinations, making the original asynchronous code more similar in form to synchronous code writing and more friendly to error handling/conditional branching/exception stack/debugging. Async and Await realize automatic iteration of Generator. Because Async and Await encapsulate the combination of Generator and Promise, Async and Await can basically only be used to realize asynchracy and concurrency. It does not have the other functions of coroutines.
The asynchronous execution of JavaScript
- All tasks are executed on the main thread, forming an execution stack. \
- In addition to the main thread, there is a “task queue”. Whenever an asynchronous task has a result, an event is placed in the “task queue”. \
- Once all synchronization tasks in the Execution stack are completed, the system reads the Task queue. Those corresponding asynchronous tasks end the wait state, enter the execution stack and begin execution.
Synchronous tasks are executed directly, while asynchronous tasks are classified into macro-tasks and micro-tasks. The current stack immediately processes all events in the microtask queue before fetching an event from the macro task queue. Microtasks are always executed before macro tasks in the same event loop.
var sleep = function (time) {
console.log("sleep start")
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve();
}, time);
});
};
async function exec() {
await sleep(2000);
console.log("sleep end")}async function go() {
console.log(Date.now())
c1 = exec()
console.log("-- -- -- -- -- -- -- 1")
c2 = exec()
console.log(c1, c2)
await c1;
console.log("-- -- -- -- -- -- -- 2")
await c2;
console.log(c1, c2)
console.log(Date.now())
}
go();
Copy the code
Event loop divides tasks into:
- The main thread loop reads events from the “task queue”
- SetTimeout, setInterval, XMLHttprequest, setImmediate, I/O, UI Rendering, etc., all of which participate in the task of the event loop.
- Micro Task (Promise), Process. nextTick (node environment), Object.observe, MutationObserver, etc., are essentially tasks performed directly in the Javascript engine without participating in the event cycle.
Best practices
- Threads and coroutines are recommended for IO intensive tasks, such as network calls, and perform poorly in CPU intensive tasks.
- For CPU-intensive tasks, multiple processes are required to bypass the GIL and utilize all available CPU cores for efficiency.
- Therefore, the best practice under large concurrency is multi-process + coroutine, which not only makes full use of multi-core, but also gives full play to the high efficiency of coroutine, and can obtain extremely high performance.
Summary: Processes, threads and coroutines are all designed to make better use of CPU resources for concurrent tasks. Their biggest difference lies in the use of CPU (task scheduling) : As mentioned above, the task scheduling of processes and threads is controlled by the kernel, which is preemptive; The task scheduling of coroutines is done in user mode, requiring explicit handing of CPU to other coroutines in code, which is collaborative.
Since we can schedule coroutine tasks in the user state, we can design a set of interdependent tasks as coroutines. In this way, when a coroutine task is completed, the task can be manually scheduled to suspend itself (yield) and switch to another coroutine. In this way, because we can control the program to voluntarily surrender resources, there will be no need to lock resources in many cases.
╭ ╮ ╱ ╭ ┳ ━ ━ ━ ┳ ╮ ╱ ╭ ╮ ┃ ┃ ╱ ┃ ┃ ╭ ━ ╮ ┃ ┃ ╱ ┃ ┃ ┃ ╰ ━ ╯ ┃ ┃ ┃ ┃ ┃ ╰ ━ ╯ ┃ ╰ ━ ━ ╮ ┃ ┃ ┃ ┃ ┣ ━ ━ ╮ ┃ ╱ ╱ ╱ ┃ ┃ ╰ ━ ╯ ┃ ╱ ╱ ┃ ┃
It is said that praise + collection == learn