Java 什么是多线程环境中的忙自旋?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25067059/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is busy spin in a multi-threaded environment?
提问by Bravo
What is "Busy Spin" in multi-threaded environment?
什么是多线程环境中的“Busy Spin”?
How it is useful and how can it be implemented in java in a multi-threaded environment?
它如何有用以及如何在多线程环境中用 java 实现?
In what way can it be useful in improving the performance of an application?
它在哪些方面有助于提高应用程序的性能?
回答by Jared
A "busy spin" is constantly looping in one thread to see if the other thread has completed some work. It is a "Bad Idea" as it consumes resources as it is just waiting. The busiest of spins don't even have a sleep in them, but spin as fast as possible waiting for the work to get finished. It is less wasteful to have the waiting thread notified by the completion of the work directly and just let it sleep until then.
“忙旋转”在一个线程中不断循环,以查看另一个线程是否已完成某些工作。这是一个“坏主意”,因为它只是在等待而消耗资源。最繁忙的旋转甚至没有睡眠,而是尽可能快地旋转等待工作完成。直接通过工作完成通知等待线程并让它休眠直到那时浪费更少。
Note, I call this a "Bad Idea", but it is used in some cases on low-level code to minimize latency, but this is rarely (if ever) needed in Java code.
请注意,我称之为“坏主意”,但它在某些情况下用于低级代码以最小化延迟,但这在 Java 代码中很少(如果有的话)需要。
回答by Vallabh Patade
Busy spin is nothing but looping over until thread(s) completes. E.g. You have say 10 threads, and you want to wait all the thread to finish and then want to continue,
忙自旋只不过是循环直到线程完成。例如,您说有 10 个线程,并且您想等待所有线程完成然后想继续,
while(ALL_THREADS_ARE_NOT_COMPLETE);
//Continue with rest of the logic
For example in java you can manage multiple thread with ExecutorService
例如在java中你可以管理多个线程 ExecutorService
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread('' + i);
executor.execute(worker);
}
executor.shutdown();
//With this loop, you are looping over till threads doesn't finish.
while (!executor.isTerminated());
It is a to busy spins as it consumes resources as CPU is not sitting ideal, but keeping running over the loop. We should have mechanism to notify the main thread (parent thread) to indicate that all thread are done and it can continue with the rest of the task.
这是一个忙碌的旋转,因为它消耗资源,因为 CPU 并不理想,而是继续在循环中运行。我们应该有机制来通知主线程(父线程)来指示所有线程都完成了,它可以继续执行剩余的任务。
With the preceding example, instead of having busy spin, you can use different mechanism to improve performance.
在前面的示例中,您可以使用不同的机制来提高性能,而不是繁忙的旋转。
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread('' + i);
executor.execute(worker);
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
log.fatal("Exception ",e);
}
回答by radar
Busy spinning/waiting is normally a bad idea from a performance standpoint. In most cases, it is preferable to sleep and wait for a signal when you are ready to run, than to do spinning. Take the scenario where there are two threads, and thread 1 is waiting for thread 2 to set a variable (say, it waits until var == true
. Then, it would busy spin by just doing
从性能的角度来看,忙于旋转/等待通常是一个坏主意。在大多数情况下,最好在准备好跑步时睡觉并等待信号,而不是进行旋转。假设有两个线程,线程 1 正在等待线程 2 设置一个变量(比如,它一直等到var == true
。然后,它会忙着旋转
while (var == false)
;
In this case, you will take up a lot of time that thread 2 can potentially be running, because when you wake up you are just executing the loop mindlessly. So, in a scenario where you are waiting for something like this to happen, it is better to let thread 2 have all control by putting yourself to sleep and having it wake you up when it is done.
在这种情况下,您将占用线程 2 可能正在运行的大量时间,因为当您醒来时,您只是在无意识地执行循环。因此,在您等待此类事情发生的情况下,最好让线程 2 拥有所有控制权,让您自己进入睡眠状态,并在完成后让它唤醒您。
BUT, in rare cases where the time you need to wait is very short, it is actually faster to spinlock. This is because of the time it takes to perform the signalng functions; spinning is preferable if the time used spinning is less than the time it would take to perform the signaling. So, in that way it may be beneficial and could actually improve performance, but this is definitely not the most frequent case.
但是,在极少数情况下,您需要等待的时间很短,实际上使用 spinlock会更快。这是因为执行信令功能需要时间;如果使用的旋转时间少于执行信令所需的时间,则旋转是可取的。因此,以这种方式它可能是有益的,并且实际上可以提高性能,但这绝对不是最常见的情况。
回答by Solomon Slow
Some of the other answers miss the real problem with busy waiting.
其他一些答案忽略了忙等待的真正问题。
Unless you're talking about an application where you are concerned with conserving electricalpower, then burning CPU time is not, in and of itself, a Bad Thing. It's only bad when there is some other thread or process that is ready-to-run. It's reallybad when one of the ready-to-run threads is the thread that your busy-wait loop is waiting for.
除非您谈论的应用程序涉及节省电力,否则消耗 CPU 时间本身并不是一件坏事。只有当有其他一些线程或进程准备好运行时,这才是糟糕的。当准备运行的线程之一是忙等待循环正在等待的线程时,这真的很糟糕。
That's the real issue. A normal, user-mode program running on a normal operating system has no control over which threads run on which processors, a normal operating system has no way to tell the difference between a thread that is busy waiting and a thread that is doing work, and even if the OS knew that the thread was busy-waiting, it would have no way to know what the thread was waiting for.
这才是真正的问题。在普通操作系统上运行的普通用户模式程序无法控制哪些线程在哪些处理器上运行,普通操作系统无法区分忙于等待的线程和正在工作的线程之间的区别,即使操作系统知道线程正在等待,它也无法知道线程在等待什么。
So, it's entirely possible for the busy waiter to wait for many milliseconds (practically an eternity), waiting for an event, while the the only thread that could make the event happen sits on the sideline (i.e., in the run queue) waiting for its turn to use a CPU.
因此,忙碌的服务员完全有可能等待许多毫秒(实际上是永恒),等待一个事件,而唯一可以使事件发生的线程坐在边线(即,在运行队列中)等待轮到使用CPU了。
Busy waiting is often used in systems where there is tight control over which threads run on which processors. Busy waiting can be the most efficient way to wait for an event when you knowthat the thread that will cause it is actually running on a different processor. That often is the case when you're writing code for the operating system itself, or when you're writing an embedded, real-time application that runs under a real-time operating system.
忙等待通常用于严格控制哪些线程在哪些处理器上运行的系统中。当您知道导致事件发生的线程实际上在不同的处理器上运行时,忙等待可能是等待事件的最有效方式。当您为操作系统本身编写代码时,或者当您编写在实时操作系统下运行的嵌入式实时应用程序时,通常就是这种情况。
Kevin Walters wrote about the case where the time to wait is very short. A CPU-bound, ordinary program running on an ordinary OS may be allowed to execute millions of instructions in each time slice. So, if the program uses a spin-lock to protect a critical section consisting of just a few instructions, then it is highly unlikely that any thread will lose its time slice while it is in the critical section. That means, if thread A finds the spin-lock locked, then it is highly likely that thread B, which holds the lock, actually isrunning on a different CPU. That's why it can be OK to use spin-locks in an ordinary program when you know it's going to run on a multi-processor host.
凯文·沃尔特斯 (Kevin Walters) 写过等待时间很短的案例。在普通操作系统上运行的受 CPU 限制的普通程序可能被允许在每个时间片中执行数百万条指令。因此,如果程序使用自旋锁来保护仅由几条指令组成的临界区,那么任何线程在处于临界区时都不太可能丢失其时间片。这意味着,如果线程A发现自旋锁锁定,则很可能该线程B,保持所述锁,实际上是在不同的CPU上运行。这就是为什么当您知道它将在多处理器主机上运行时,在普通程序中使用自旋锁是可以的。
回答by SHA
Busy-waiting or spinning is a technique in which a process repeatedly checks to see if a condition is true instead of calling wait or sleep method and releasing CPU.
忙等待或自旋是一种技术,其中进程重复检查条件是否为真,而不是调用等待或睡眠方法并释放 CPU。
1.It is mainly useful in multicore processor where condition is going to be true quite quickly i.e. in millisecond or micro second
1.它主要用于多核处理器,条件很快就会成立,即毫秒或微秒
2.Advantage of not releasing CPU is that, all cached data and instruction are remained unaffected, which may be lost, had this thread is suspended on one core and brought back to another thread
2.不释放CPU的好处是,所有缓存的数据和指令不受影响,可能会丢失,如果这个线程在一个内核上挂起并带回另一个线程
回答by Martin Kersten
Spin Waiting is that you constantly wait for a condition comes true. The opposite is waiting for a signal (like thread interruption by notify() and wait()).
Spin Waiting 是您不断等待条件成立。相反的是等待信号(如notify() 和wait() 引起的线程中断)。
There are two ways of waiting, first semi-active (sleep / yield) and active (busy waiting).
有两种等待方式,第一种是半主动(sleep/yield)和主动(忙等待)。
On busy waiting a program idles actively using special op codes like HLT or NOP or other time consuming operations. Other use just a while loop checking for a condition comming true.
在忙等待时,程序会使用特殊操作码(如 HLT 或 NOP 或其他耗时操作)主动空闲。其他用途只是一个 while 循环检查条件是否成立。
The JavaFramework provides Thread.sleep, Thread.yield and LockSupport.parkXXX() methods for a thread to hand over the cpu. Sleep waits for a specific amount of time but alwasy takes over a millisecond even if a nano second was specified. The same is true for LockSupport.parkNanos(1). Thread.yield allows for a resolution of 100ns for my example system (win7 + i5 mobile).
JavaFramework 提供了 Thread.sleep、Thread.yield 和 LockSupport.parkXXX() 方法让一个线程交出 CPU。Sleep 等待特定的时间量,但即使指定了纳秒,也总是需要超过一毫秒。LockSupport.parkNanos(1) 也是如此。Thread.yield 允许我的示例系统(win7 + i5 mobile)的分辨率为 100ns。
The problem with yield is the way it works. If the system is utilized fully yield can take up to 800ms in my test scenario (100 worker threads all counting up a number (a+=a;) indefinitively). Since yield frees the cpu and adds the thread to the end of all threads within its priority group, yield is therefore unstable unless the cpu is not utilized to a certain extend.
yield 的问题在于它的工作方式。如果系统被完全利用,在我的测试场景中可能需要 800 毫秒(100 个工作线程都不确定地计数一个数字 (a+=a;))。由于yield 释放cpu 并将线程添加到其优先级组内的所有线程的末尾,因此yield 因此不稳定,除非cpu 未被使用到一定程度。
Busy waiting will block a CPU (core) for multiple milliseconds.
忙等待将阻塞 CPU(核心)数毫秒。
The Java Framework (check Condition class implementations) uses active (busy) wait for periodes less then 1000ns (1 microsecond). At my system an average invocation of System.nanoTime takes 160ns so busy waiting is like checking the condition spend 160ns on nanoTime and repeat.
Java 框架(检查 Condition 类实现)使用小于 1000ns(1 微秒)的活动(忙)等待时间。在我的系统中,System.nanoTime 的平均调用需要 160ns,所以忙于等待就像检查条件在 nanoTime 上花费 160ns 并重复。
So basically the concurrency framework of Java (queues etc) has something like wait under a microsecond spin and hit the waiting periode within a N granulairty where N is the number of nanoseconds for checking time constraints and wait for one ms or longer (for my current system).
所以基本上 Java 的并发框架(队列等)有类似在微秒旋转下等待并在 N 粒度内达到等待周期,其中 N 是检查时间约束的纳秒数并等待一毫秒或更长时间(对于我目前的系统)。
So active busy waiting increases utilization but aid in the overall reactiveness of the system.
因此,主动忙等待增加了利用率,但有助于系统的整体反应性。
While burning CPU time one should use special instructions reducing the power consumption of the core executing the time consuming operations.
在消耗 CPU 时间的同时,应使用特殊指令来降低执行耗时操作的内核的功耗。
回答by roottraveller
Busy spin is one of the technique to wait for events without releasing CPU. It's often done to avoid losing data in CPU cached which is lost if the thread is paused and resumed in some other core.
Busy spin 是一种在不释放 CPU 的情况下等待事件的技术。通常这样做是为了避免丢失 CPU 缓存中的数据,如果线程在其他内核中暂停和恢复,则数据会丢失。
So, if you are working on low latency system where your order processing thread currently doesn't have any order, instead of sleeping or calling wait()
, you can just loop and then again check the queue for new messages. It's only beneficial if you need to wait for a very small amount of time e.g. in micro seconds or nano seconds.
因此,如果您正在使用低延迟系统,您的订单处理线程当前没有任何订单,而不是 sleep 或 call wait()
,您可以循环然后再次检查队列中是否有新消息。只有当您需要等待非常短的时间(例如微秒或纳秒)时,它才有用。
LMAX Disrupter framework, a high-performance inter-thread messaging library has a BusySpinWaitStrategy which is based on this concept and uses a busy spin loop for EventProcessors waiting on the barrier.
LMAX Disrupter 框架是一个高性能的线程间消息传递库,它有一个 BusySpinWaitStrategy,它基于这个概念,并为在屏障上等待的 EventProcessor 使用忙碌的自旋循环。