skip to content

In JMeter's HTTP Request, what does the Parallel downloads number actually limit?

level: seniorimportance: nice to knowfreq 28%

answer

  1. A per-sampler cap, not a global one
  2. Six unless you change it
  3. Threads named after the downloader
  4. Setting it to one changes nothing

basics

~20 s

It limits how many of that one sampler's embedded-resource requests are in flight at once, per execution. It does not limit the shared downloader thread pool, which has no maximum and grows with the number of JMeter threads.

solid answer

~40 s

The checkbox and number are `HTTPSampler.concurrentDwn` and `HTTPSampler.concurrentPool`, the latter defaulting to `6`. For one sampler execution JMeter submits at most that many extracted URLs at a time and waits for one to complete before submitting the next, so twenty assets at six go out in waves. The tasks all run on a **single process-wide** executor, `ResourcesDownloader`, built with core size 1, maximum `Integer.MAX_VALUE` and a `SynchronousQueue` — so a task never queues, a new thread is created instead. Its threads are daemon, named `ResDownload-…`, and reclaimed after `httpsampler.parallel_download_thread_keepalive_inseconds` seconds of idleness (default 60). Two hundred JMeter threads at six each can therefore hold well over a thousand downloader threads.

code

properties · 8 lines
properties
# keep alive time for the parallel download threads (in seconds)
httpsampler.parallel_download_thread_keepalive_inseconds=60

# do not keep embedded resource bodies, only size and MD5
httpsampler.embedded_resources_use_md5=false

# a failed embedded resource marks the parent failed
httpsampler.ignore_failed_embedded_resources=false

go deeper

for a junior

Know the checkbox exists next to Retrieve All Embedded Resources and that the number beside it defaults to six.

for a middle

Explain the wave behaviour: at most n assets in flight per sampler execution, the rest submitted as earlier ones complete.

for a senior

Reason about what the setting costs on the generator — a shared, unbounded pool of daemon ResDownload threads with a sixty-second idle keep-alive — and recognise those threads in a thread listing.

for a principal

Set the house value and say why: how much concurrency per page sampler is worth the extra threads and sockets, and whether the setting belongs on each sampler or once on HTTP Request Defaults.

**Parallel downloads. Number:** sits beside the *Retrieve All Embedded Resources* checkbox on the HTTP Request's Advanced tab. In the `.jmx` it is two properties: `HTTPSampler.concurrentDwn` for the checkbox and `HTTPSampler.concurrentPool` for the number, which defaults to `6`. ## What the number bounds It bounds **this sampler's own in-flight asset requests**, for the one execution that is running. JMeter builds the list of extracted URLs, then submits at most `n` of them to a completion service and waits for one to finish before submitting the next. So a page with twenty assets and a number of 6 sends them in waves of six, and the sampler's container elapsed time drops from the sum of twenty-one requests to roughly the page plus four waves. ## What the number does not bound The executor those tasks are submitted to is a **process-wide singleton**, `ResourcesDownloader`. It is constructed as a thread pool with: - a core size of `1`; - a maximum size of `Integer.MAX_VALUE` — effectively unbounded; - a `SynchronousQueue`, so a task never waits in a queue; if no thread is free, a new one is created; - a thread factory that names threads `ResDownload-…` and marks them daemon; - an idle keep-alive taken from `httpsampler.parallel_download_thread_keepalive_inseconds`, default `60` seconds. Every JMeter thread that hits a parallel-download sampler shares that one pool. The per-sampler number caps *each* caller, but nothing caps the total. Two hundred threads each allowed six concurrent asset fetches can put on the order of twelve hundred `ResDownload-` threads on the load generator, and they linger for a minute after they go idle before the pool reclaims them. ## Things you can check 1. A thread dump or any thread listing shows the pool directly: the names all start with `ResDownload-`. 2. `httpsampler.parallel_download_thread_keepalive_inseconds` controls how long idle downloader threads survive; shortening it trades thread churn for a smaller resident count between waves. 3. At the end of a test JMeter calls the pool's `shrink()`, which purges the queue, cancels anything still pending and drops the maximum size back to one so the extra threads can be released. ## Two edge cases worth remembering **A number of 1 is not "serial with a pool".** JMeter checks for it explicitly, logs `Number of parallel downloads set to 1, (sampler name=…)` and falls back to the ordinary serial path on the sampler's own thread. No task ever reaches the pool. **A non-numeric value is not an error.** If the field does not parse as an integer, JMeter logs `Concurrent download resources selected, but pool size value is bad. Use default value` and quietly uses `6`. A field holding an unresolved variable therefore gives you six, not a failed run. ## How to reason about the setting The number is a *shape* control for one sampler's container timing, not a throughput control for the run. Raising it makes each page sampler finish sooner and makes the container's elapsed time look more like a browser's page-load time; it also multiplies the concurrent sockets and threads the generator holds. Judging whether the generator can carry that, and whether the resulting offered load still means anything, are separate topics — what belongs to the sampler is knowing that the number you typed is per-sampler and that the pool behind it has no ceiling of its own.

  • What happens if you set the Parallel downloads number to 1?
    JMeter detects it, logs `Number of parallel downloads set to 1` with the sampler name, and reverts to the ordinary serial path on the sampler's own thread. No task is submitted to the downloader pool at all, so the setting behaves exactly as if the checkbox were unticked.
  • The number field holds an unresolved variable at run time. What pool size is used?
    Six. JMeter parses the field as an integer and, on failure, logs `Concurrent download resources selected, but pool size value is bad. Use default value` and continues with the built-in default of 6. The run is not aborted and the sample is not marked bad.

saying these in an interview costs you the question

  • Calls it a global cap on concurrent asset downloads
  • Says the downloader pool has a fixed maximum size
  • Thinks setting it to one enables a one-thread pool
  • Assumes a bad value aborts the run
  • Believes downloader threads exit the moment a wave ends