# Questions about asych calls and threads

**URL:** <https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633>\
**Category:** Ignition\
**Tags:** perspective, vision, scripting\
**Created:** [October 22, 2024, 7:27pm UTC](https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633 "2024-10-22T19:27:42Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![David.Reed.Schmidt](https://avatars.discourse-cdn.com/v4/letter/d/5f9b8f/32.png) [@David.Reed.Schmidt](https://forum.inductiveautomation.com/u/David.Reed.Schmidt)\
**Post date:** [October 22, 2024, 7:27pm UTC](https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633/1 "2024-10-22T19:27:42Z")

</div>

Is there a comprehensive guide on how to maximize asynchronous calls and thread management in Ignition? I make a lot of asynchronous calls because my code crunches a lot of SQL data which can take a bit of time. I realize that locking the UI isn't as much an issue in Perspective as it was in Vision but I still like to run asynchronous calls for more complicated calls. In fact I use Python decorators to easily change my functions to run asynchronously. And now I don't hesitate to make my functions run asynchronously. Also, someone in the office mentioned that Ignition will only run three threads and any additional asynchronous calls get put in a pool waiting execution. If so then what is the point of making an asynchronous call? I looked in the documentation and found very little detail about this topic.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [October 22, 2024, 7:40pm UTC](https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633/2 "2024-10-22T19:40:45Z")

</div>

> [@David.Reed.Schmidt](#):
>
> Also, someone in the office mentioned that Ignition will only run three threads and any additional asynchronous calls get put in a pool waiting execution.

That someone is mixing things up. Tag events (defined directly on tags) run in a thread pool of size three.

There's no limit to asynchronous threads, except that they consume CPU time without constraint.

Running asynchronously adds thread-switching overhead, each of which needs to start up a jython interpreter context. You should not be running asynchronously for most tasks. Consider deliberately creating thread pools of fixed size for specific purposes, and delegate tasks to those.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 22, 2024, 10:29pm UTC](https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633/3 "2024-10-22T22:29:08Z")

</div>

So, question for the group (not _just_ Phil, who is definitely not a representative sample of our customer base 😉) -

What would 1. make sense and 2. be useful?

Some kind of project-scoped thread pool on the gateway, with a `system.util.pushToTaskQueue(payload)`?  
Some kind of `system.util.threadPool([parameters])` function, that internally wraps a thread pool? Or maybe a project/gateway resource where you _configure_ a thread pool, and then you retrieve it by name with `system.util.threadPool([name])`, and push work into it?

I'm not interested in serializing code state or replacing the SFC module, but threads are (relatively) heavyweight, so it'd be good to have an nicer idiomatic way to use them than _just_ `invokeAsynchronous`. Plus scheduled thread pools let you run things on fixed delays, making for a very easy replacement for folks use of `time.sleep`.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [October 22, 2024, 11:15pm UTC](https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633/4 "2024-10-22T23:15:44Z")

</div>

> [@paul-griffith](#):
>
> for the group

Hmmm. David and I are in this topic, but how many others will this question reach?

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [October 22, 2024, 11:15pm UTC](https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633/5 "2024-10-22T23:15:48Z")

</div>

> [@paul-griffith](#):
>
> Or maybe a project/gateway resource where you _configure_ a thread pool, and then you retrieve it by name with `system.util.threadPool([name])`, and push work into it?

I like this one, I think it’s a good trade off between ease of use and discouraging creation of thread pools all willy-nilly.

---

<div class="post-metadata">

**Author:** ![David.Reed.Schmidt](https://avatars.discourse-cdn.com/v4/letter/d/5f9b8f/32.png) [@David.Reed.Schmidt](https://forum.inductiveautomation.com/u/David.Reed.Schmidt)\
**Post date:** [October 23, 2024, 12:31am UTC](https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633/6 "2024-10-23T00:31:30Z")

</div>

In general, how would I create a thread pool? Say I was going to run 20 process heavy Python functions all at once, no more and no less.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [October 23, 2024, 11:28am UTC](https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633/7 "2024-10-23T11:28:59Z")

</div>

There's an example in my [later.py](https://www.automation-pros.com/ignition/later.py) helper script that makes a single thread pool. Do similar, but set it to 20.

{ I probably aught to simplify that example a bit, and replace `system.util.persistent()` with `system.util.globalVarMap()`. }

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [October 23, 2024, 12:15pm UTC](https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633/8 "2024-10-23T12:15:25Z")

</div>

> [@paul-griffith](#):
>
> `system.util.threadPool([parameters])` function, that internally wraps a thread pool? Or maybe a project/gateway resource where you _configure_ a thread pool, and then you retrieve it by name with `system.util.threadPool([name])`, and push work into it?

I would vote for this one. I think it fits well with the current ecosystem.

Might be nice to have the ability to target a vision client scope as well.

---

<div class="post-metadata">

**Author:** ![Alex\_Ceithamer](https://avatars.discourse-cdn.com/v4/letter/a/a3d4f5/32.png) [@Alex\_Ceithamer](https://forum.inductiveautomation.com/u/Alex_Ceithamer)\
**Post date:** [January 29, 2025, 10:15pm UTC](https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633/9 "2025-01-29T22:15:02Z")

</div>

> [@paul-griffith](#):
>
> Or maybe a project/gateway resource where you _configure_ a thread pool, and then you retrieve it by name with `system.util.threadPool([name])`, and push work into it?

I would also vote for this one. Preferably with the ability to configure the pool to run on the gateway or client (depending on the use case, one may want to offload the work onto the gateway or keep it on the client)

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [January 29, 2025, 10:25pm UTC](https://forum.inductiveautomation.com/t/questions-about-asych-calls-and-threads/97633/10 "2025-01-29T22:25:21Z")

</div>

I would only support such a `threadPool()` if it tied itself to the lifetime of the scripting environment, killing off pending tasks on scripting restart, refusing new tasks at that point, and killing any running tasks within a few seconds. It is otherwise extremely unsafe (memory leaking) if given tasks with long durations, scheduled more than a few seconds in the future, or anything repeating.

I strongly encourage construction of queues holding native jython or java objects **instead of code**. More details here (read the whole topic):

> [@Java concurrent queue for tag change scripts](https://forum.inductiveautomation.com/t/java-concurrent-queue-for-tag-change-scripts/82044):
>
> Continuing the discussion from [[SOLVED] Are tag Value Changed scripts running asynchronously?](https://forum.inductiveautomation.com/t/solved-are-tag-value-changed-scripts-running-asynchronously/68704/5): We've got code in our standard library that I need to log a value change on a tag and then associate various data points with that value change. The value is located in a UDT, and because this is part of our "standard" library we use for our customers, the number of tags is variable and quite possibly numerous so having a gateway tag event script isn't feasible for this solution. I was reading up on …
