diff --git a/platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java b/platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java index ae8182a5bb8f..52c58a152515 100644 --- a/platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java +++ b/platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java @@ -123,20 +123,14 @@ class ApplierCompleter extends CountedCompleter { @Nullable private ApplierCompleter execAndForkSubTasks() { int hi = this.hi; - long start = System.currentTimeMillis(); ApplierCompleter right = null; Throwable throwable = null; try { for (int i = lo; i < hi; ++i) { ProgressManager.checkCanceled(); - if (!processor.process(array.get(i))) { - throw new ComputationAbortedException(); - } - long finish = System.currentTimeMillis(); - long elapsed = finish - start; - if (elapsed > 1 && hi - i >= 2) { - int availableParallelism = JobSchedulerImpl.getJobPoolParallelism() - getSurplusQueuedTaskCount(); + if (hi - i >= 2) { + int availableParallelism = JobSchedulerImpl.getJobPoolParallelism() - Math.max(0,getSurplusQueuedTaskCount()); if (availableParallelism > 1) { // fork off several sub-tasks at once to reduce rampup for (int n=0; n extends CountedCompleter { right.fork(); hi = mid; } - start = finish; } } + if (!processor.process(array.get(i))) { + throw new ComputationAbortedException(); + } } // traverse the list looking for a task available for stealing diff --git a/platform/platform-tests/testSrc/com/intellij/concurrency/JobUtilTest.java b/platform/platform-tests/testSrc/com/intellij/concurrency/JobUtilTest.java index e8b65ac109fb..e3003c94eacf 100644 --- a/platform/platform-tests/testSrc/com/intellij/concurrency/JobUtilTest.java +++ b/platform/platform-tests/testSrc/com/intellij/concurrency/JobUtilTest.java @@ -44,7 +44,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -import static com.intellij.util.TestTimeOut.*; + +import static com.intellij.util.TestTimeOut.setTimeout; public class JobUtilTest extends LightPlatformTestCase { private static final AtomicInteger COUNT = new AtomicInteger(); @@ -538,4 +539,35 @@ public class JobUtilTest extends LightPlatformTestCase { if (!stealHappened.get()) break; // tested that we wanted } } + + public void testInvokeConcurrentlyMustExecuteMultipleTasksConcurrentlyEvenIfOneOfThemIsWildlySlow() { + int N = 8; + Integer[] times = new Integer[N]; + for (int i=0; i { + while ((time -= 100) >= 0) { + ProgressManager.checkCanceled(); + TimeoutUtil.sleep(100); + } + + if (executed.incrementAndGet() == times.length - 1) { + // executed all but the slowest one + throw new RuntimeException(enough); + } + return true; + }); + fail(); + } + catch (RuntimeException e) { + assertEquals(enough, e.getMessage()); + } + } + } }