# Async limit

**URL:** <https://discourse.julialang.org/t/async-limit/62732>\
**Category:** New to Julia\
**Tags:** question\
**Created:** [June 11, 2021, 12:30pm UTC](https://discourse.julialang.org/t/async-limit/62732 "2021-06-11T12:30:58Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![gitboy16](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gitboy16/32/24906_2.png) [@gitboy16](https://discourse.julialang.org/u/gitboy16)\
**Post date:** [June 11, 2021, 12:30pm UTC](https://discourse.julialang.org/t/async-limit/62732/1 "2021-06-11T12:30:58Z")

</div>

Hi,

When using `@async` is there a way to limit the number of processes/queries being run at the same time?

Thank you  
Kind regards

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [August 1, 2021, 5:49pm UTC](https://discourse.julialang.org/t/async-limit/62732/2 "2021-08-01T17:49:57Z")

</div>

It is reasonable to use a semaphore for this, as described here for threads:

> [@Control number of threads](https://discourse.julialang.org/t/control-number-of-threads/62887/3):
>
> Semaphore You can use what ever threading solution you want. (Including Threads.@threads ) plus a [Base.Semaphore](https://docs.julialang.org/en/v1/base/parallel/#Base.Semaphore) to control number of threads active at a time. Something like using Threads sem = Base.Semaphore(2) # at most 2 at a time Threads.@threads for ii in 1:100 Base.acquire(sem) println(threadid()) Base.release(sem) end This will ensure only 2 threads are doing anything at a time. THough which two may change (and in the case of Threads.@thread will because of how it all…

I have also seen a `Channel` used as a adhoc semaphore.  
Which is marginally faster since it is not having to take out locks etc.  
but probably not worth the loss of clarity for code.  
Plus using a semaphore frees you to change from tasks to threads later.  
(threads are just tasks without the sticky bit set)

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [August 1, 2021, 9:23pm UTC](https://discourse.julialang.org/t/async-limit/62732/3 "2021-08-01T21:23:04Z")

</div>

I recommend using “worker pool” pattern I described in a quick tutorial [Concurrency patterns for controlled parallelisms](https://juliafolds.github.io/data-parallelism/tutorials/concurrency-patterns/) ([discussion](https://discourse.julialang.org/t/tutorial-concurrency-patterns-for-controlled-parallelisms/62651)) which is just a simple wrapper around a channel and tasks.

Semaphore may be useful for simple things sometimes but lock and lock-like constructs often yield non-composable and hard-to-read code. “Don’t communicate by sharing memory, share memory by communicating.” is one of very practical [Go Proverbs](https://go-proverbs.github.io/). Since a lot of good practical ideas in concurrency are developed in Go, I think it’d be useful to steal some patterns from Go. Some of them are discussed in my tutorial I linked above.

It is also a waste of resource to allocate tasks and _then_ limit how many of them can run. It is usually much cleaner to match the bound and the number of tasks in the first place, in terms of performance and code structure.

> [@oxinabox](#):
>
> I have also seen a `Channel` used as a adhoc semaphore.  
> Which is marginally faster since it is not having to take out locks etc.

`Channel` uses lock internally.

> [@oxinabox](#):
>
> change from tasks to threads later

A nitpick: There’s no way in Julia to “change tasks to threads.” There is no language-level API to create an OS thread. The only thing you can do is to create a _task_ which comes with two flavors:

- A _task_ scheduled with `Threads.@spawn` can be executed by arbitrary worker threads.
- A task scheduled with `@async` uses the same worker thread as the parent task.

(I’m sure you already know this since you are mentioning the “sticky bit.” This is rather for avoiding confusion of other readers.)

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [August 2, 2021, 12:06am UTC](https://discourse.julialang.org/t/async-limit/62732/4 "2021-08-02T00:06:03Z")

</div>

> [@tkf](#):
>
> `Channel` uses lock internally.

So they do.  
This was not the case in 1.2, it was changed in 1.3.  
Makes sense, we started taking multithreading seriously in 1.3,  
but I thought that the `Base.Channel` didn’t have a lock, and only the `Base.Threads.Channel` had a lock; but no: `Base.Threads.Channel === Base.Channel`
