2

I have the following scenario:

I am listening file requests and when one arrives, I am starting download task in a new thread. After download task ends, a process task starts but this is important, process task must wait for download task. To do that, I can use dt_thread.join() or just stop using thread and download in blocking way. But in both cases, upcoming file requests get blocked and this turns out to be a performance issue.

I need to handle download tasks in threads but also need to ensure that process tasks start after relevant download task.

What kind of thread logic can I apply?

public void activateListener() {
    fileRequestService.listen((name) -> {
        DownloadTask dt = new DownloadTask(); // DownloadTask implements Runnable
        Thread dt_thread = new Thread(dt);
        dt_thread.start();

        ProcessTask pt = new ProcessTask(); // ProcessTask implements Runnable
        Thread pt_thread = new Thread(pt);
        pt_thread.start();       
    }
}
2
  • (1) You can address the perceived performance overhead issue about threads by using a thread pool executor. That way, creating new tasks become less of an issue. (2) You can also use Semaphore to limit the number of active downloads to one, but do pay attention to the first-come-first-serve issue (which is not what Semaphore offers; a blocking queue may be needed), which is different from fairness.
    – rwong
    Sep 12, 2020 at 5:51
  • But I do not want to limit the number of active downloads to one, a lot of should happen at the same time but each process should wait its relative download.
    – Davis
    Sep 12, 2020 at 6:53

1 Answer 1

3

If I understand well your question, the performance issues may be caused by delays on a download task or delays in a processing task, which delay the processing of further files by your listener.

This is because, despite your thread, you have fundamentally a sequential pipeline. The only advantage of the threads is that your system is not frozen and other unrelated thread can continue their job.

You would gain a higher throughput by using a streaming architecture where worker-tasks process work when they are ready, deoupling the sequence:

                           +------------+
                           |  Listener  |
                           +------------+
                                  |
                                  V
                +---------------------------------------+
Request queue:  | ... // "file3" // "file2" //  "file1" |
                +---------------------------------------+
                                  |
                                 /|\         
              +-------------+              +-------------+
Download:     | DL Worker 1 |      ...     | DL Worker n |
(threads)     +-------------+              +-------------+
                                 \|/                               
                                  |
                +---------------------------------------+
Downloaded:     |  ... // f_file0 // f_file1 // ...     |
(Queue)         +---------------------------------------+
                                  |
                                 /|\         
              +-------------+              +-------------+
Process:      | PR Worker 1 |      ...     | PR Worker n |
(threads)     +-------------+              +-------------+
                                 \|/                               
                                  |
                +---------------------------------------+
Processed:      |  ... // result1 // result3 // ...     |
(queue)         +---------------------------------------+
                                  |
                                  V
                        +-----------------+
                        |  Serve results  |
                        +-----------------+

This allows a non-blocking maximal throughput: any delay, would just delay the processing of a single task without affecting the others.

There are a lot of variants. For example:

  • If the output order matters, or the order of the start of processing matters, you'd need to add some ordering logic in the queue (i.e. an sequential ID), so that the queue ensure the ordering of its elements.
  • If the processing order in general matters (i.e. no processing should be carried out before the rprevious processed work is completed), you could replace the processing workers with a single worker (like the result server), with the above mentioned sequential ID, that allows to check that the next expected data download is finished.
5
  • Thanks for detailed answer. So, when a download task arrives, I should put it to downloadTaskQueue fo type BlockingQueue. Process result does not matter so I do not use process queue. As soon as I can consume from downloadTaskQueue, I just just match the download task id and process task id so that each process operations process relative download task result.
    – Davis
    Sep 12, 2020 at 13:47
  • @Davis yes. If the blocking is only expected in the download, this is an option that simplifies the overall picture.
    – Christophe
    Sep 12, 2020 at 13:49
  • Download blocks relative process task but different downloads happen at the same time. Thank you much
    – Davis
    Sep 12, 2020 at 13:54
  • I still could not figure out the queue (blocking queue) scenario here. A hand would be great. What I am thinking is to queue incoming download file task and as soon as one is queued start downloading it via method like offerAndDownload(). Then what? After download, should I remove it from queue? When to use get method? Why should I use another queue for processin tasks? I really got stuck in use of queue here.
    – Davis
    Sep 13, 2020 at 15:45
  • @Davis sorry, yes: the queue is the mean to distribute the tasks. You enqueue the work to be done (filenames to download, objects refering to downloaded files,...) and the task that does the job dequeue the first available work and process it (that's the simplest way, a variant is to keep elements in the queue and mark them as in process, but this kind of controls would make the whole things much more complex)
    – Christophe
    Sep 13, 2020 at 17:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.