Groovy 如何使用GPAR知道抛出异常时所有线程都已完成?
在线程抛出异常的情况下,如何等待所有未抛出异常的线程都完成(这样用户在所有线程停止之前不会再次启动) 我以几种不同的方式使用GPAR,因此我需要针对每种方式使用一种策略(并行集合、异步闭包和fork/join)。异常不会被掩埋,它们通过承诺、getChildrenResults等得到了很好的处理,因此这不是一个问题(感谢Vaclav Pech的回答)。我只需要确保主线程等待任何仍在运行的完成或停止 例如,当使用并行集合时,有些线程继续运行,而有些线程在异常发生后从不启动。因此,要知道有多少人在那里等待,或者可能要抓住他们并不容易 我猜可能有一种方法可以使用线程池(本例中是GParsPool)。有什么建议吗Groovy 如何使用GPAR知道抛出异常时所有线程都已完成?,groovy,gpars,Groovy,Gpars,在线程抛出异常的情况下,如何等待所有未抛出异常的线程都完成(这样用户在所有线程停止之前不会再次启动) 我以几种不同的方式使用GPAR,因此我需要针对每种方式使用一种策略(并行集合、异步闭包和fork/join)。异常不会被掩埋,它们通过承诺、getChildrenResults等得到了很好的处理,因此这不是一个问题(感谢Vaclav Pech的回答)。我只需要确保主线程等待任何仍在运行的完成或停止 例如,当使用并行集合时,有些线程继续运行,而有些线程在异常发生后从不启动。因此,要知道有多少人在那
谢谢 我相信您将需要捕获异常,然后返回预期结果以外的内容(例如,如果您期望的是数字,则返回字符串或null),即
我相信您将需要捕获异常,然后返回预期结果以外的内容(例如,如果您期望的是数字,则返回字符串或null),即
我相信我已经找到了解决这个问题的方法,在经过彻底测试后,我在应用程序中实现了它,并且可以正常工作 withPool闭包作为第一个参数传入创建的池(jsr166y.ForkJoinPool)。我可以获取它并将其存储在一个变量(currentPool)中,稍后由主线程使用,如下所示:
GParsPool.withPool { pool ->
currentPool = pool
当抛出异常并返回到主线程进行处理时,我可以让它等待所有事情完成,如下所示:
} catch (Exception exc) {
if (currentPool) {
while (!currentPool.isQuiescent()) {
Thread.sleep(100)
println 'waiting for threads to finish'
}
}
println 'all done'
}
isquisite()似乎是确保没有更多工作要做的安全方法
请注意,在测试期间,我还发现异常似乎并不像我最初认为的那样终止循环的执行。如果我有一个500人的列表,并且每个人都并行,那么不管第一个到第二个是否有错误,他们都会运行。因此,我必须在并行循环的异常处理程序中使用currentPool.shutdownNow()终止循环。另见:
以下是实际解决方案的完整简化表示:
void example() {
jsr166y.ForkJoinPool currentPool
AtomicInteger threadCounter = new AtomicInteger(0)
AtomicInteger threadCounterEnd = new AtomicInteger(0)
AtomicReference<Exception> realException = new AtomicReference<Exception>()
try {
GParsPool.withPool { pool ->
currentPool = pool
(1..500).eachParallel {
try {
if (threadCounter.incrementAndGet() == 1) {
throw new RuntimeException('planet blew up!')
}
if (realException.get() != null) {
// We had an exception already in this eachParallel - quit early
return
}
// Do some long work
Integer counter=0
(1..1000000).each() {counter++}
// Flag if we went all the way through
threadCounterEnd.incrementAndGet()
} catch (Exception exc) {
realException.compareAndSet(null, exc)
pool.shutdownNow()
throw realException
}
}
}
} catch (Exception exc) {
// If we used pool.shutdownNow(), we need to look at the real exception.
// This is needed because pool.shutdownNow() sometimes generates a CancellationException
// which can cover up the real exception that caused us to do a shutdownNow().
if (realException.get()) {
exc = realException.get()
}
if (currentPool) {
while (!currentPool.isQuiescent()) {
Thread.sleep(100)
println 'waiting for threads to finish'
}
}
// Do further exception handling here...
exc.printStackTrace()
}
}
void示例(){
jsr166y.ForkJoinPool当前池
AtomicInteger线程计数器=新的AtomicInteger(0)
AtomicInteger threadCounterEnd=新的AtomicInteger(0)
AtomicReference realException=新的AtomicReference()
试一试{
GParsPool.withPool{pool->
当前池=池
(1..500)。每个平行{
试一试{
if(threadCounter.incrementAndGet()==1){
抛出新的RuntimeException('星球爆炸!')
}
if(realeexception.get()!=null){
//我们在这场平行赛中已经出现了一个例外——提前退出
返回
}
//做些长时间的工作
整数计数器=0
(1..1000000).each(){counter++}
//旗子,如果我们一路通过
threadCounterEnd.incrementAndGet()
}捕获(异常exc){
realException.compareAndSet(null,exc)
pool.shutdownNow()
抛出realException
}
}
}
}捕获(异常exc){
//如果我们使用pool.shutdownNow(),我们需要查看真正的异常。
//这是必需的,因为pool.shutdownNow()有时会生成CancellationException
//这可以掩盖导致我们执行Shutdownow()的真正异常。
if(realeexception.get()){
exc=realeexception.get()
}
如果(当前池){
而(!currentPool.isquisite()){
线程。睡眠(100)
println“等待线程完成”
}
}
//在此执行进一步的异常处理。。。
exc.printStackTrace()
}
}
回到我前面的例子,如果我在4核机器上第一次抛出异常,大约有5个线程排队。shutdownNow()会在大约20个线程通过后切断连接,因此在顶部附近进行“提前退出”检查有助于这20个左右的线程尽快退出
只是把它贴在这里,以防它帮助了其他人,作为我在这里得到的所有帮助的回报。谢谢 我相信我已经找到了解决这个问题的方法,经过彻底的测试后,我在应用程序中实现了它,它可以正常工作 withPool闭包作为第一个参数传入创建的池(jsr166y.ForkJoinPool)。我可以获取它并将其存储在一个变量(currentPool)中,稍后由主线程使用,如下所示:
GParsPool.withPool { pool ->
currentPool = pool
当抛出异常并返回到主线程进行处理时,我可以让它等待所有事情完成,如下所示:
} catch (Exception exc) {
if (currentPool) {
while (!currentPool.isQuiescent()) {
Thread.sleep(100)
println 'waiting for threads to finish'
}
}
println 'all done'
}
isquisite()似乎是确保没有更多工作要做的安全方法
请注意,在测试期间,我还发现异常似乎并不像我最初认为的那样终止循环的执行。如果我有一个500人的列表,并且每个人都并行,那么不管第一个到第二个是否有错误,他们都会运行。因此,我必须在并行循环的异常处理程序中使用currentPool.shutdownNow()终止循环。另见:
以下是实际解决方案的完整简化表示:
void example() {
jsr166y.ForkJoinPool currentPool
AtomicInteger threadCounter = new AtomicInteger(0)
AtomicInteger threadCounterEnd = new AtomicInteger(0)
AtomicReference<Exception> realException = new AtomicReference<Exception>()
try {
GParsPool.withPool { pool ->
currentPool = pool
(1..500).eachParallel {
try {
if (threadCounter.incrementAndGet() == 1) {
throw new RuntimeException('planet blew up!')
}
if (realException.get() != null) {
// We had an exception already in this eachParallel - quit early
return
}
// Do some long work
Integer counter=0
(1..1000000).each() {counter++}
// Flag if we went all the way through
threadCounterEnd.incrementAndGet()
} catch (Exception exc) {
realException.compareAndSet(null, exc)
pool.shutdownNow()
throw realException
}
}
}
} catch (Exception exc) {
// If we used pool.shutdownNow(), we need to look at the real exception.
// This is needed because pool.shutdownNow() sometimes generates a CancellationException
// which can cover up the real exception that caused us to do a shutdownNow().
if (realException.get()) {
exc = realException.get()
}
if (currentPool) {
while (!currentPool.isQuiescent()) {
Thread.sleep(100)
println 'waiting for threads to finish'
}
}
// Do further exception handling here...
exc.printStackTrace()
}
}
void示例(){
jsr166y.ForkJoinPool当前池
AtomicInteger线程计数器=新的AtomicInteger(0)
原子霉素