简体   繁体   English

非阻塞 IO 与异步 IO 以及 Java 中的实现

[英]non-blocking IO vs async IO and implementation in Java

Trying to summarize for myself the difference between these 2 concepts (because I'm really confused when I see people are using both of them in one sentence, like "non-blocking async IO" which I'm trying to figure out what does it mean).试图为自己总结这两个概念之间的区别(因为当我看到人们在一个句子中同时使用这两个概念时,我真的很困惑,例如“非阻塞异步 IO”,我试图弄清楚它是什么意思)。

So, in my understanding non-blocking IO is primary the OS mechanism to process the IO if there is any data ready, otherwise just return error/do nothing.因此,在我的理解中,非阻塞 IO 是主要的操作系统机制来处理 IO,如果有任何数据准备好,否则就返回错误/什么都不做。

In async IO you just provide a callback, and your application will be notified when the data is available.在异步 IO 中,您只需提供一个回调,当数据可用时,您的应用程序将收到通知。

So what is actually "non-blocking async IO"?那么究竟什么是“非阻塞异步 IO”? And how all them can be implemented in Java (standard JDK, without external libs, I know there are java.nio.channels.{Channels, Selector, SelectorKey} and java.nio.channels.{AsynchronousSocketChannel} ): non-blocking IO, async IO, and non-blocking async IO (if there is such thing)?以及它们如何在 Java 中实现(标准 JDK,没有外部库,我知道有java.nio.channels.{Channels, Selector, SelectorKey}java.nio.channels.{AsynchronousSocketChannel} ):非阻塞 IO ,异步IO,和非阻塞异步IO(如果有的话)?

I see this is an old question, but I think something was missed here, that @nickdu attempted to point out but wasn't quite clear.我看到这是一个老问题,但我认为这里遗漏了一些东西,@nickdu 试图指出但不太清楚。

There are four types of IO pertinent to this discussion:有四种类型的 IO 与此讨论相关:

Blocking IO阻塞IO

Non-Blocking IO非阻塞 IO

Asynchronous IO异步IO

Asynchronous Non-Blocking IO异步非阻塞 IO

The confusion arises I think because of ambiguous definitions.我认为混淆是因为定义不明确。 So let me attempt to clarify that.所以让我试着澄清一下。

First Let's talk about IO.先说IO。 When we have slow IO this is most apparent, but IO operations can either be blocking or non-blocking.当我们有慢速 IO 时这是最明显的,但是 IO 操作可以是阻塞的也可以是非阻塞的。 This has nothing to do with threads, it has to do with the interface to the operating system.这与线程无关,它与操作系统的接口有关。 When I ask the OS for an IO operation I have the choice of waiting for all the data to be ready ( blocking ), or getting what is available right now and moving on ( non-blocking ).当我要求操作系统进行 IO 操作时,我可以选择等待所有数据准备就绪(阻塞),或者获取现在可用的数据并继续(非阻塞)。 The default is blocking IO.默认为阻塞 IO。 It is much easier to write code using blocking IO as the path is much clearer.使用阻塞 IO 编写代码要容易得多,因为路径更清晰。 However, your code has to stop and wait for IO to complete.但是,您的代码必须停止并等待 IO 完成。 Non-Blocking IO requires interfacing with the IO libraries at a lower level, using select and read/write instead of the higher level libraries that provide convenient operations.非阻塞 IO 需要在较低级别与 IO 库接口,使用选择和读/写代替提供方便操作的较高级别库。 Non-Blocking IO also implies that you have something you need to work on while the OS works on doing the IO.非阻塞 IO 还意味着您需要在操作系统处理 IO 时处理一些事情。 This might be multiple IO operations or computation on the IO that has completed.这可能是已完成的 IO 上的多个 IO 操作或计算。

Blocking IO - The application waits for the OS to gather all the bytes to complete the operation or reach the end before continuing.阻塞 IO - 应用程序在继续之前等待操作系统收集所有字节以完成操作或到达末尾。 This is default.这是默认设置。 To be more clear for the very technical, the system call that initiates the IO will install a signal handler waiting for a processor interrupt that will occur when the IO operation makes progress.为了更清楚地了解技术性,启动 IO 的系统调用将安装一个信号处理程序,等待 IO 操作进行时将发生的处理器中断。 Then the system call will begin a sleep which suspends operation of the current process for a period of time, or until the process interrupt occurs.然后系统调用将开始休眠,暂停当前进程的操作一段时间,或者直到进程中断发生。

Non-Blocking IO - The application tells the OS it only wants what bytes are available right now, and moves on while the OS concurrently gathers more bytes.非阻塞 IO - 应用程序告诉操作系统它只想要现在可用的字节,并在操作系统同时收集更多字节时继续前进。 The code uses select to determine what IO operations have bytes available.该代码使用 select 来确定哪些 IO 操作具有可用字节。 In this case the system call will again install a signal handler, but rather than sleep, it will associate the signal handler with the file handle, and immediately return.在这种情况下,系统调用将再次安装信号处理程序,但不是休眠,而是将信号处理程序与文件句柄相关联,并立即返回。 The process will become responsible for periodically checking the file handle for the interrupt flag having been set.该进程将负责定期检查已设置的中断标志的文件句柄。 This is usually done with a select call.这通常通过 select 调用完成。

Now Asynchronous is where the confusion begins.现在异步是混乱开始的地方。 The general concept of asynchronous only implies that the process continues while the background operation is performed, the mechanism by which this occurs is not specific.异步的一般概念仅意味着在执行后台操作时进程继续,发生这种情况的机制并不具体。 The term is ambiguous as both non-blocking IO and threaded blocking IO can be considered to be asynchronous.该术语含糊不清,因为非阻塞 IO 和线程阻塞 IO 都可以被认为是异步的。 Both allow concurrent operations, however the resource requirements are different, and the code is substantially different.两者都允许并发操作,但是资源需求不同,代码也大不相同。 Because you have asked a question "What is Non-Blocking Asynchronous IO", I am going to use a stricter definition for asynchronous, a threaded system performing IO which may or may not be non-blocking.因为您已经问过“什么是非阻塞异步 IO”的问题,所以我将对异步使用更严格的定义,即执行 IO 的线程系统可能是非阻塞的,也可能不是。

The general definition一般定义

Asynchronous IO - Programmatic IO which allows multiple concurrent IO operations to occur.异步 IO - 允许多个并发 IO 操作发生的编程 IO。 IO operations are happening simultaneously, so that code is not waiting for data that is not ready. IO 操作同时发生,因此代码不会等待未准备好的数据。

The stricter definition更严格的定义

Asynchronous IO - Programmatic IO which uses threading or multiprocessing to allow concurrent IO operations to occur.异步 IO - 编程 IO,它使用线程或多处理来允许并发 IO 操作发生。

Now with those clearer definitions we have the following four types of IO paradigms.现在有了这些更清晰的定义,我们有了以下四种类型的 IO 范式。

Blocking IO - Standard single threaded IO in which the application waits for all IO operations to complete before moving on.阻塞 IO - 标准单线程 IO,其中应用程序在继续之前等待所有 IO 操作完成。 Easy to code, no concurrency and so slow for applications that require multiple IO operations.易于编码,没有并发性,对于需要多个 IO 操作的应用程序来说很慢。 The process or thread will sleep while waiting for the IO interrupt to occur.进程或线程将在等待 IO 中断发生时休眠。

Asynchronous IO - Threaded IO in which the application uses threads of execution to perform Blocking IO operations concurrently.异步 IO - 线程 IO,其中应用程序使用执行线程并发执行阻塞 IO 操作。 Requires thread safe code, but is generally easier to read and write than the alternative.需要线程安全代码,但通常比替代方法更易于读写。 Gains the overhead of multiple threads, but has clear execution paths.获得多线程的开销,但具有清晰的执行路径。 May require the use of synchronized methods and containers.可能需要使用同步方法和容器。

Non-Blocking IO - Single threaded IO in which the application uses select to determine which IO operations are ready to advance, allowing the execution of other code or other IO operations while the OS processes concurrent IO.非阻塞 IO - 单线程 IO,其中应用程序使用 select 来确定哪些 IO 操作准备好进行,允许在操作系统处理并发 IO 时执行其他代码或其他 IO 操作。 The process does not sleep while waiting for the IO interrupt, but takes on the responsibility to check for the IO flag on the filehandle.该进程在等待 IO 中断时不会休眠,而是负责检查文件句柄上的 IO 标志。 Much more complicated code due to the need to check the IO flag with select, though does not require thread-safe code or synchronized methods and containers.由于需要使用 select 检查 IO 标志,因此代码更加复杂,但不需要线程安全代码或同步方法和容器。 Low execution over-head at the expense of code complexity.以代码复杂性为代价的低执行开销。 Execution paths are convoluted.执行路径是复杂的。

Asynchronous Non-Blocking IO - A hybrid approach to IO aimed at reducing complexity by using threads, while maintaining scalability by using non-blocking IO operations where possible.异步非阻塞 IO - 一种混合 IO 方法,旨在通过使用线程降低复杂性,同时在可能的情况下通过使用非阻塞 IO 操作来保持可伸缩性。 This would be the most complex type of IO requiring synchronized methods and containers, as well as convoluted execution paths.这将是最复杂的 IO 类型,需要同步方法和容器,以及复杂的执行路径。 This is not the type of IO that one should consider coding lightly, and is most often only used when using a library that will mask the complexity, something like Futures and Promises.这不是人们应该轻松考虑编码的 IO 类型,并且通常仅在使用会掩盖复杂性的库时使用,例如 Futures 和 Promises。

So what is actually "non-blocking async IO"?那么究竟什么是“非阻塞异步 IO”?

To answer that, you must first understand that there's no such thing as blocking async I/O .要回答这个问题,您必须首先了解没有阻塞异步 I/O之类的东西。 The very concept of asynchronism dictates that there's no waiting, no blocking, no delay.异步的概念要求没有等待,没有阻塞,没有延迟。 When you see non-blocking asynchronous I/O , the non-blocking bit only serves to further qualify the async adjective in that term.当您看到非阻塞异步 I/O 时非阻塞位仅用于进一步限定该术语中的异步形容词。 So effectively, non-blocking async I/O might be a bit of a redundancy.如此有效地,非阻塞异步 I/O可能有点冗余。

There are mainly two kinds of I/O.主要有两种I/O。 Synchronous and Asynchronous .同步异步 Synchronous blocks the current thread of execution until processing is complete , while Asynchronous doesn't block the current thread of execution, rather passing control to the OS Kernel for further processing. Synchronous 阻塞当前执行线程直到处理完成,而Asynchronous 不会阻塞当前执行线程,而是将控制权传递给 OS Kernel 进行进一步处理。 The kernel then advises the async thread when the submitted task is complete当提交的任务完成时,内核然后通知异步线程


Asynchronous Channel Groups异步通道组

The concept of Async Channels in java is backed by Asynchronous Channel Groups. java中异步通道的概念是由异步通道组支持的。 An async channel group basically pools a number of channels for reuse.异步通道组基本上汇集了许多通道以供重用。 Consumers of the async api retrieve a channel from the group (the JVM creates one by default) and the channel automatically puts itself back into the group after it's completed its read/write operation.异步 api 的使用者从组中检索通道(JVM 默认创建一个),通道在完成读/写操作后自动将自己放回组中。 Ultimately, Async Channel Groups are backed by surprise , threadpools.最终,异步通道组得到了意外的支持,线程池。 Also, Asynchronous channels are threadsafe.此外,异步通道是线程安全的。

The size of the threadpool that backs an async channel group is configured by the following JVM property支持异步通道组的线程池的大小由以下 JVM 属性配置

java.nio.channels.DefaultThreadPool.initialSize

which, given an integer value will setup a threadpool of that size, to back the channel group.其中,给定一个整数值将设置一个该大小的线程池,以支持通道组。 The channel group is created and maintained transparently to the developer otherwise.否则,通道组的创建和维护对开发人员是透明的。


And how all them can be implemented in Java以及如何在 Java 中实现所有这些

Well, I'm glad you asked.嗯,我很高兴你问。 Here's an example of an AsynchronousSocketChannel (used to open a non-blocking client Socket to a listening server.) This sample is an excerpt from Apress Pro Java NIO.2 , commented by me:下面是一个AsynchronousSocketChannel的例子(用于打开一个非阻塞客户端Socket到一个监听服务器。)这个例子是Apress Pro Java NIO.2的摘录,由我评论:

//Create an Asynchronous channel. No connection has actually been established yet
AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open(); 

/**Connect to an actual server on the given port and address. 
   The operation returns a type of Future, the basis of the all 
   asynchronous operations in java. In this case, a Void is 
   returned because nothing is returned after a successful socket connection
  */
Void connect = asynchronousSocketChannel.connect(new InetSocketAddress("127.0.0.1", 5000)).get();


//Allocate data structures to use to communicate over the wire
ByteBuffer helloBuffer = ByteBuffer.wrap("Hello !".getBytes()); 

//Send the message

Future<Integer> successfullyWritten=  asynchronousSocketChannel.write(helloBuffer);

//Do some stuff here. The point here is that asynchronousSocketChannel.write() 
//returns almost immediately, not waiting to actually finish writing 
//the hello to the channel before returning control to the currently executing thread

doSomethingElse();

//now you can come back and check if it was all written (or not)

System.out.println("Bytes written "+successfullyWritten.get());

EDIT: I should mention that support for Async NIO came in JDK 1.7编辑:我应该提到对 Async NIO 的支持来自 JDK 1.7

I would say there are three types of io:我会说有三种类型的io:

synchronous blocking同步阻塞
synchronous non-blocking同步非阻塞
asynchronous异步

Both synchronous non-blocking and asynchronous would be considered non-blocking as the calling thread is not waiting on the IO to complete.同步非阻塞和异步都将被视为非阻塞,因为调用线程不等待 IO 完成。 So while non-blocking asynchronous io might be redundant, they are not one in the same.因此,虽然非阻塞异步 io 可能是多余的,但它们并不相同。 When I open a file I can open it in non-blocking mode.当我打开一个文件时,我可以在非阻塞模式下打开它。 What does this mean?这是什么意思? It means when I issue a read() it won't block.这意味着当我发出 read() 它不会阻塞。 It will either return me the bytes that are available or indicate that there are no bytes available.它要么返回可用字节,要么指示没有可用字节。 If I didn't enable non-blocking io the read() would block until data was available.如果我没有启用非阻塞 io,则 read() 将阻塞,直到数据可用。 I might want to enable non-blocking io if I want a thread to handle multiple io requests.如果我想要一个线程处理多个 io 请求,我可能想要启用非阻塞 io。 For instance, I could use select() to find out what file descriptors, or maybe sockets, have data available to read.例如,我可以使用 select() 找出哪些文件描述符或套接字具有可供读取的数据。 I then do synchronous reads on those file descriptors.然后我对这些文件描述符进行同步读取。 None of those reads should block because I already know data is available, plus I have opened the file descriptors in non-blocking mode.这些读取都不应该阻塞,因为我已经知道数据可用,而且我已经在非阻塞模式下打开了文件描述符。

Asynchronous io is where you issue an io request.异步 io 是您发出 io 请求的地方。 That request is queued, and thus doesn't block the issuing thread.该请求已排队,因此不会阻塞发出线程。 You are notified when either the request failed or has completed successfully.当请求失败或成功完成时,您会收到通知。

Non blocking IO is when the call to perform IO returns immediately, and does not block your thread.非阻塞 IO是指执行 IO 的调用立即返回,并且不会阻塞您的线程。

The only way to know if the IO is done, is to poll its status or block.知道 IO 是否完成的唯一方法是轮询其状态或阻止。 Think of it as a Future .把它想象成一个Future You start an IO operation, and it returns you a Future .你开始一个 IO 操作,它会返回一个Future You can call isDone() on it to check if its done, if it is, do what you want with it, otherwise keep doing other stuff until the next time you want to check if its done.你可以调用isDone()来检查它是否完成,如果是,就用它做你想做的事情,否则继续做其他事情,直到下次你想检查它是否完成。 Or, if you're out of things to do, you can call get on it, which will block until its done.或者,如果你无事可做,你可以调用get on it,它会阻塞直到它完成。

Async IO is when the call to perform IO notifies you it is done through an event, not through its return value.异步 IO是指执行 IO 的调用通知您它已通过事件完成,而不是通过其返回值。

This can be blocking or non-blocking.这可以是阻塞的或非阻塞的。

Blocking Async IO阻塞异步 IO

What is meant by blocking async IO is that the call to perform IO is a normal blocking call, but the thing you called wrapped that call inside a thread which will block until the IO is done and then delegate the handling of the result of the IO to your callback.阻塞异步 IO 的意思是执行 IO 的调用是一个正常的阻塞调用,但是您调用的东西将该调用包装在一个线程中,该线程将阻塞直到 IO 完成,然后委托处理 IO 的结果到您的回调。 That is, there is still a thread lower down the stack which is blocked on the IO, but your thread isn't.也就是说,仍然有一个线程在 IO 上阻塞的堆栈下方,但您的线程不是。

Non-blocking Async IO非阻塞异步 IO

This is actually the more common one, and it means that the non-blocking IO does not need to be polled for its status, as with standard non-blocking IO, instead it will call your callback when its done.这实际上是更常见的一种,这意味着非阻塞 IO 不需要像标准非阻塞 IO 那样轮询其状态,而是在完成后调用您的回调。 As opposed to blocking async IO, this one has no threads blocked anywhere down the stack, thus its faster and uses less resources, as the asynchronous behavior is managed without blocking threads.与阻塞异步 IO 不同,这个线程在堆栈的任何地方都没有阻塞,因此它更快并且使用更少的资源,因为异步行为是在不阻塞线程的情况下进行管理的。

You can think of it as a CompletableFuture .您可以将其视为CompletableFuture It requires that your program has some form of async event framework, which can be multi-threaded or not.它要求您的程序具有某种形式的异步事件框架,该框架可以是多线程的,也可以不是。 So its possible the callback is executed in another thread, or that it is scheduled for execution on an existing thread once the current task is done.因此,回调可能在另一个线程中执行,或者在当前任务完成后安排在现有线程上执行。

I explain the distinction more thoroughly here.我在这里更彻底地解释了这种区别

Synchronous vs. asynchronous同步与异步

Asynchronous is a relative term that applies to all kinds of computation, not just IO.异步是一个相对术语,适用于所有类型的计算,而不仅仅是 IO。 Something can not be asynchronous by itself but always to something else.某些东西不能单独异步,而总是其他东西异步 Usually, asynchronicity means that some operation is happening in a different thread of execution relative to the thread that requested the IO computation, and there is no explicit synchronization (waiting) between a requesting and a computing threads.通常,异步性意味着某些操作发生在与请求 IO 计算的线程不同的执行线程中,并且在请求线程和计算线程之间没有显式同步(等待)。 If a requesting thread waits (sleeps, blocks) while the computing thread is doing its work, we call such an operation synchronous.如果一个请求线程在计算线程执行其工作时等待(休眠、阻塞),我们称这种操作为同步操作。 There are also mixed cases.也有混合情况。 Sometimes a requesting thread doesn't wait immediately and performs some fixed amount of useful work asynchronously after issuing an IO request, but later blocks (synchronizes) to await for the IO results if they are not yet readily available.有时,请求线程不会立即等待,而是在发出 IO 请求后异步执行一些固定数量的有用工作,但稍后会阻塞(同步)以等待 IO 结果(如果它们尚不可用)。

Blocking vs. non-blocking阻塞与非阻塞

In the broader sense, "blocking" and "non-blocking" can roughly be used to denote "synchronous" and "asynchronous" correspondingly.从广义上讲,“阻塞”和“非阻塞”可以粗略地分别表示“同步”和“异步”。 You will often encounter "blocking" to be used interchangeably with "synchronous" and "non-blocking" with "asynchronous".您经常会遇到“阻塞”与“同步”和“非阻塞”与“异步”互换使用。 In this sense, "non-blocking asynchronous" is redundant as other folks mentioned above.从这个意义上说,“非阻塞异步”就像上面提到的其他人一样是多余的。

However, in a more narrow sense "blocking" and "non-blocking" may refer to different kernel IO interfaces.然而,狭义上的“阻塞”和“非阻塞”可能指的是不同的内核 IO 接口。 It's worth saying here that all IO operations these days are performed by the OS kernel because access to IO hardware devices such as disks or network interface cards is abstracted away by the OS.这里值得一提的是,现在所有的 IO 操作都是由 OS 内核执行的,因为对 IO 硬件设备(例如磁盘或网络接口卡)的访问被 OS 抽象掉了。 It means that every IO operation that you request from your userspace code will end up being executed by the kernel via either blocking or non-blocking interface.这意味着您从用户空间代码请求的每个 IO 操作最终都将由内核通过阻塞或非阻塞接口执行。

When called via the blocking interface, the kernel will assume that your thread wants to obtain results synchronously and will put it to sleep (deschedule, block) until the IO results are available.当通过阻塞接口调用时,内核会假设您的线程想要同步获取结果,并将其置于睡眠状态(取消调度、阻塞),直到 IO 结果可用。 Therefore that thread will not be able to do any other useful work while the kernel is fulfilling the IO request.因此,当内核正在执行 IO 请求时,该线程将无法执行任何其他有用的工作。 As an example, all disk IO on Linux is blocking.例如,Linux 上的所有磁盘 IO 都是阻塞的。

Non-blocking kernel interfaces work differently.非阻塞内核接口的工作方式不同。 You tell the kernel which IO operations you want.你告诉内核你想要哪些 IO 操作。 The kernel doesn't block (deschedule) your thread and returns from the IO call immediately.内核不会阻塞(取消调度)您的线程并立即从 IO 调用返回。 Your thread can then move on and do some useful work.然后您的线程可以继续并做一些有用的工作。 Kernel threads will fulfill the IO requests asynchronously.内核线程将异步完成 IO 请求。 Your code then needs to check occasionally if the kernel has already done its job, after which you can consume the results.然后您的代码需要偶尔检查内核是否已经完成其工作,之后您可以使用结果。 As an example, Linux provides the epoll interface for the non-blocking IO.例如,Linux 为非阻塞 IO 提供了epoll接口。 There are also older poll and select system calls for the same purpose.出于相同目的,还有较旧的pollselect系统调用。 It's worth noting that non-blocking interfaces mostly apply and are used for networking.值得注意的是,非阻塞接口主要应用于网络。

Please, note that the fact that some higher-level IO APIs use blocking kernel IO under the hood doesn't mean that your thread will necessarily block when calling that API.请注意,某些更高级别的 IO API 在后台使用阻塞内核 IO 的事实并不意味着您的线程在调用该 API 时一定会阻塞。 Such an API may implement a mechanism to spawn a new or use a different existing thread to perform that blocking IO.这样的 API 可以实现一种机制来产生新的或使用不同的现有线程来执行该阻塞 IO。 It will notify your calling thread later through some means (a callback, an event, or by letting your thread poll) that it has completed the IO request.稍后它将通过某种方式(回调、事件或让您的线程轮询)通知您的调用线程它已完成 IO 请求。 Ie, non-blocking IO semantics can be implemented in userspace by third-party libraries or runtimes on top of the blocking OS kernel interfaces by using additional threads.即,非阻塞 IO 语义可以由第三方库或运行时在用户空间中通过使用附加线程在阻塞 OS 内核接口之上实现。

Conclusion结论

To understand how each particular runtime or library achieves IO asynchronicity, you will have to go deeper and find out if it spawns new threads or relies upon asynchronous kernel interfaces.要了解每个特定的运行时或库如何实现 IO 异步性,您必须更深入地了解它是产生新线程还是依赖于异步内核接口。

Afterword后记

Realistically, there is very little chance you will encounter genuinely single-threaded systems these days.实际上,如今您几乎没有机会遇到真正的单线程系统。

As en example, most people will refer to Node.js as having a "single-threaded non-blocking" IO.例如,大多数人会将 Node.js 称为具有“单线程非阻塞”IO。 However, this is a simplification.然而,这是一种简化。 On Linux, truly non-blocking IO is only available for network operations through the epoll interface.在 Linux 上,真正的非阻塞 IO 只能通过epoll接口进行网络操作。 For disk IO, the kernel will always block the calling thread.对于磁盘 IO,内核将始终阻塞调用线程。 To achieve asynchronicity for disk IO (which is relatively slow), Node.js runtime (or libuv to be precise) maintains a dedicated thread pool.为了实现磁盘 IO 的异步性(相对较慢),Node.js 运行时(或libuvlibuv )维护了一个专用线程池。 Whenever an asynchronous disk IO operation is requested, the runtime assigns the work to one of the threads from that pool.每当请求异步磁盘 IO 操作时,运行时都会将工作分配给该池中的线程之一。 That thread will do standard blocking disk IO, while the main (calling) thread will go on asynchronously.该线程将执行标准的阻塞磁盘 IO,而主(调用)线程将异步进行。 Not to mention numerous threads, which are maintained separately by V8 runtime for garbage collection and other managed runtime tasks.更不用说许多线程,它们由 V8 运行时单独维护,用于垃圾收集和其他托管运行时任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM