This is a creation in Article, where the information may have evolved or changed.
Even if I die, buried in the land, I will use my rotten vocal cords shout out: Idle CPU is shameful. --Confucius
Process, thread? Parallel, concurrency?
Because of the single-core CPU performance surplus, and so high performance can only run a program is undoubtedly a great waste, so the multi-tasking operating system came into being.
The operating system maps each task to a process, with each process running in turn by CPU polling, which makes people think that all processes are running at the same time, and that there is actually only one process running at the same time, which is called concurrency . When the CPU is multi-core or multi-threaded, at the same time there will be multiple processes running simultaneously, which is called parallel .
With the progress of the times, more and more business logic needs high concurrency and needs high performance. Because of the creation process, the switching process, inter-process communication, the high cost , so that multiple processes work together and can not meet the requirements, so multithreading came into being. By creating multiple threads in each process, these threads share a process data, which almost compensates for all the drawbacks of a multi-process. Today's mainstream operating systems are multi-threaded operating systems, such as: Windows,linux, a thread for the operating system minimum scheduling unit, through the scheduler, for each thread to allocate time slices.
With the improvement of hardware performance, with the test of time, the shortcomings of multi-process become the disadvantage of multithreading: Creating threads, switching threads, communication between threads, high cost. because single-core CPU performance is sufficient, many times the need is concurrency, not parallelism. Both the process and the thread are taken over by the system, and both concurrency and parallelism are the system's final decisions. Therefore, people crave only concurrent multi-threading, thus the Association process came into being.
What is a co-process?
Consider:
Multiple threads process their respective queues, and when the queue has a task, the thread executes sequentially, and when the queue is empty, the thread sleeps, so it loops.
If the number of threads is thousands or tens, and these threads have only a few queues at the same time, the operating system will suspend threads frequently, activate threads, and all threads will consume system resources, which can overwhelm the system and make the system slow even if only a few threads are running, even if each thread needs a lock. Although there are many lock-free algorithms, this can make programming difficult from normal to hell, while manipulating threads, the lock time may be much greater than the time the thread executes the task.
If we can have their own thread scheduler, can be at the application layer at random to dispatch threads, to avoid threads into the kernel state, to avoid thread contention for resources, reduce thread switching overhead, can be in a single-core CPU high concurrent squeeze dry performance, such multithreading is the Association Process .
If you use a co-process to complete the above tasks, you can solve all of the above shortcomings.
Because the scheduler is too low-level, almost the entire language fixed, so only those for the high concurrency of the language, there will be a scheduler, such as: Golang,erlang, etc., these languages are suitable for writing high concurrency programs. For languages that are not intended for high concurrency, they also require a process, but they do not require a scheduler, which is sufficient if they are manually dispatched.
Replacing asynchronous callbacks with a co-process
LUA has a co-process, no scheduler, even so, the association is still one of the most powerful features of Lua, this feature is often ignored by the novice, because they have no idea how to use the association process.
function f() f1() f2() f3()end
The above code logic is very clear, the f() function is executed sequentially, f1() f2() f3() for some reason , perhaps animation delay , perhaps the network request , perhaps intentionally delayed , f1() f2() You can't get the results right away, and you can't let the line measuring modules wait. As a result, this becomes an asynchronous requirement, and the code may become the following:
function f() f1(function() f2(f3) end)end
The above logic seems to be very clear,,, f1() f2() all accept a function as an asynchronous callback, but in the f1() argument, there is a noticeable disharmony code, because f3() the parameters to be used to f2() function() end produce a closure to pass. However, once more functions need to be executed, the code will be miserable:
function f() f1(function() f2(function() f3(function() f4(f5) end) end) end)end
Go back to the previous section of code:
function f() f1(function() f2(f3) end)end
This code async callback function only 3, seemingly logical clear, in fact there is a major hidden trouble, from the f() function body, can only see f1() , f2() respectively, accept a function as a parameter, and can not be clear f1() , f2() f3() whether to call in order (Perhaps the internal does not touch this parameter), thus making the f() logic is not clear, even the internal execution order can not be guaranteed. If there are a large number of asynchronous callbacks, the degree of logical confusion is not unimaginable, commonly known as: callback Hell .
Is it possible to make an asynchronous call or to write like a synchronous call? Can be done with a co-process.
local function async(handler) local runn = coroutine.running() handler(function() coroutine.resume(runn) end) coroutine.yield()endfunction f() local co = coroutine.create(function() async(f1) async(f2) async(f3) ... async(fN) end) coroutine.resume(co)end
f()Internally f1() ,, f2() , ... fN() called asynchronously, this code appears to be synchronous, but it is indeed asynchronous. It is true that the process can gracefully solve the problem of callback hell, which is not fixed and can be coded according to specific requirements.
The above code principle is:
Using a co-process to execute the first asynchronous function, while jumping back to the main program, because the process is in the same thread as the main program, so the call in the process is the same as in the main program call, when the asynchronous call completes and then jumps back to the coprocessor, continues the next asynchronous call, so loop.
Asynchronous callbacks are not without advantages. For example, simple problems can be complicated, complex problems to make a lot of problems, so that developers live every day to enrich.