When do I schedule a ReadTask?

I have some analysis that I want to run every time the current file changes. The analysis can take a few seconds, so I need to cancel it whenever the user types more, then restart the analysis.

In the documentation for ReadTask, it says to schedule another task if it gets cancelled before finishing. I wrote a little example task that just runs a timer for five seconds while checking for cancellation. When I look at the log, I see it gets cancelled and restarted several times, and then it runs for a few seconds. If I type another letter before it finishes, it gets cancelled and restarts, but the documentChanged() handler schedules a second task. Now I have two sets of tasks running in parallel, each cancelling and restarting several times before they can get started. If I type a third letter, I end up with three tasks in parallel.

Do I have to check whether the analysis has finished in documentChanged(), and only schedule a new task if the old one finished? Is it normal for there to be so many write actions that keep cancelling my analysis? Is there an easier strategy for running a background task? How do the code inspections run?

Here's my little example:

private void logThread(String message) {
String name = Thread.currentThread().getName();
if (name.length() > 35) {
name = name.substring(0, 35);
}
log.info(String.format(
"[%s] %s",
name,
message));
}

private class AnalysisTask extends ReadTask {
private Document document;

AnalysisTask(Document document) {
this.document = document;
}

@Nullable
@Override
public Continuation performInReadAction(@NotNull ProgressIndicator indicator) throws ProcessCanceledException {
String sourceCode = document.getText();
logThread("Starting " + toString() + " with " + sourceCode);
for (int i = 0; i < 500; i++) {
try {
Thread.sleep(10);
indicator.checkCanceled();
} catch (ProcessCanceledException | InterruptedException e) {
logThread("cancelled " + toString() + " with " + sourceCode);
return null;
}
}
logThread("Finished " + toString() + " with " + sourceCode);
return null;
}

@Override
public void onCanceled(@NotNull ProgressIndicator indicator) {
logThread("onCanceled " + toString());
schedule(document);
}
}

@Override
public void documentChanged(DocumentEvent e) {
if (isRunning) {
logThread("document changed");
schedule(e.getDocument());
}
}

private void schedule(Document document) {
ProgressIndicatorUtils.scheduleWithWriteActionPriority(new AnalysisTask(document));
}

Here is the log output when I type "abc" into an empty file:

2017-10-27 21:25:51,080 [ 559075]   INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] document changed
2017-10-27 21:25:51,085 [ 559080] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 21] Starting ...AnalysisTask@7a021782 with a
2017-10-27 21:25:51,085 [ 559080] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] onCanceled ...AnalysisTask@7a021782
2017-10-27 21:25:51,095 [ 559090] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 21] cancelled ...AnalysisTask@7a021782 with a
2017-10-27 21:25:51,097 [ 559092] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 21] Starting ...AnalysisTask@75f6e03 with a
2017-10-27 21:25:51,100 [ 559095] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] onCanceled ...AnalysisTask@75f6e03
2017-10-27 21:25:51,108 [ 559103] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 21] cancelled ...AnalysisTask@75f6e03 with a
2017-10-27 21:25:51,110 [ 559105] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 21] Starting ...AnalysisTask@3ddd9096 with a
2017-10-27 21:25:51,110 [ 559105] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] onCanceled ...AnalysisTask@3ddd9096
2017-10-27 21:25:51,120 [ 559115] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 21] cancelled ...AnalysisTask@3ddd9096 with a
2017-10-27 21:25:51,121 [ 559116] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 21] Starting ...AnalysisTask@5bad3529 with a
2017-10-27 21:25:52,087 [ 560082] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] onCanceled ...AnalysisTask@5bad3529
2017-10-27 21:25:52,092 [ 560087] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 21] cancelled ...AnalysisTask@5bad3529 with a
2017-10-27 21:25:52,094 [ 560089] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] document changed
2017-10-27 21:25:52,101 [ 560096] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 2] Starting ...AnalysisTask@6e7fa33d with ab
2017-10-27 21:25:52,107 [ 560102] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 18] Starting ...AnalysisTask@39268d1b with ab
2017-10-27 21:25:52,107 [ 560102] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] onCanceled ...AnalysisTask@6e7fa33d
2017-10-27 21:25:52,107 [ 560102] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] onCanceled ...AnalysisTask@39268d1b
2017-10-27 21:25:52,111 [ 560106] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 2] cancelled ...AnalysisTask@6e7fa33d with ab
2017-10-27 21:25:52,117 [ 560112] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 18] cancelled ...AnalysisTask@39268d1b with ab
2017-10-27 21:25:52,119 [ 560114] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 2] Starting ...AnalysisTask@24b2a450 with ab
2017-10-27 21:25:52,119 [ 560114] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 18] Starting ...AnalysisTask@2bb75a5b with ab
2017-10-27 21:25:53,325 [ 561320] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] onCanceled ...AnalysisTask@2bb75a5b
2017-10-27 21:25:53,325 [ 561320] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] onCanceled ...AnalysisTask@24b2a450
2017-10-27 21:25:53,328 [ 561323] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 18] cancelled ...AnalysisTask@2bb75a5b with ab
2017-10-27 21:25:53,328 [ 561323] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 2] cancelled ...AnalysisTask@24b2a450 with ab
2017-10-27 21:25:53,330 [ 561325] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] document changed
2017-10-27 21:25:53,339 [ 561334] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 18] Starting ...AnalysisTask@73b4e4d5 with abc
2017-10-27 21:25:53,342 [ 561337] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 2] Starting ...AnalysisTask@4a7674b1 with abc
2017-10-27 21:25:53,344 [ 561339] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 22] Starting ...AnalysisTask@5cb85d77 with abc
2017-10-27 21:25:53,344 [ 561339] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] onCanceled ...AnalysisTask@73b4e4d5
2017-10-27 21:25:53,344 [ 561339] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] onCanceled ...AnalysisTask@4a7674b1
2017-10-27 21:25:53,344 [ 561339] INFO - .livepycharm.LiveCodingAnalyst - [AWT-EventQueue-0 2017.1.4#IC-171.46] onCanceled ...AnalysisTask@5cb85d77
2017-10-27 21:25:53,349 [ 561344] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 18] cancelled ...AnalysisTask@73b4e4d5 with abc
2017-10-27 21:25:53,353 [ 561348] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 2] cancelled ...AnalysisTask@4a7674b1 with abc
2017-10-27 21:25:53,354 [ 561349] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 22] cancelled ...AnalysisTask@5cb85d77 with abc
2017-10-27 21:25:53,356 [ 561351] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 18] Starting ...AnalysisTask@4f93c336 with abc
2017-10-27 21:25:53,356 [ 561351] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 22] Starting ...AnalysisTask@77b39476 with abc
2017-10-27 21:25:53,356 [ 561351] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 2] Starting ...AnalysisTask@70395dcc with abc
2017-10-27 21:25:58,426 [ 566421] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 18] Finished ...AnalysisTask@4f93c336 with abc
2017-10-27 21:25:58,436 [ 566431] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 22] Finished ...AnalysisTask@77b39476 with abc
2017-10-27 21:25:58,436 [ 566431] INFO - .livepycharm.LiveCodingAnalyst - [ApplicationImpl pooled thread 2] Finished ...AnalysisTask@70395dcc with abc

 

0
正式评论

The easiest way seems to have an Alarm where "cancelAllRequests" and "schedule" are called on both cancellation and document change. Then these events would be merged and only a single bg task would be run (after the alarm timeout passes). Editor highlighting works in a similar way.

Thanks, Peter, I didn't know about the Alarm class.

0

请先登录再写评论。