# Threading 1.3: Success Story

**URL:** https://discourse.julialang.org/t/threading-1-3-success-story/27111
**Category:** Internals & Design
**Created:** [August 2, 2019, 1:16pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111 "2019-08-02T13:16:20Z")
**Posts on this page:** 17
**Page:** 1

<div class="post-metadata">

### Author: ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)
#### Post date: [August 2, 2019, 1:16pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/1 "2019-08-02T13:16:20Z")

</div>

Dear @jeff.bezanson and @jameson. Just want to share a success story for the new threading infrastructure (1.3 alpha). The focus in your Juliacon talk seemed to be primary on performance but from my perspective a very important advantage is asynchronous UI programming. In UI programming it is very common to move all work to threads such that the UI remains responsive. This was not really doable until Julia 1.3. The following Gtk example shows what is now possible. One clicks a button and a progress bar is updated regularly, depending on the work done. When running the code with one thread, the entire application freezes. When using more than one thread, everything works as expected.

What is not 100% clear to me is if it is actually allowed to update the UI on the thread. If not one would need to handle over the work to the UI thread somehow. Maybe spawn a task that is scheduled on the main thread.

```julia
using Gtk.ShortNames

b = Box(:v)
win = Window(b,"test")

button = Button("do work")
push!(b,button)

pb = ProgressBar()
push!(b,pb)

Gtk.showall(win)

function doWork()
  N = 20
  for k=1:N
    set_gtk_property!(pb,:fraction,(k-1)/(N-1) )
    sum(collect(1:100000000)) # some heavy work
  end
end

signal_connect(button, "clicked") do widget
  Threads.@spawn doWork()
end

```

---

<div class="post-metadata">

### Author: ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)
#### Post date: [August 2, 2019, 1:32pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/2 "2019-08-02T13:32:29Z")

</div>

To answer the question myself, the following runs the UI updating code on the main thread again:

```julia
using Gtk.ShortNames

b = Box(:v)
win = Window(b,"test")

button = Button("do work")
push!(b,button)

pb = ProgressBar()
push!(b,pb)

Gtk.showall(win)

function doWork()
  N = 20
  for k=1:N
    Gtk.GLib.g_idle_add(nothing) do user_data
      set_gtk_property!(pb,:fraction,(k-1)/(N-1) )
      Cint(false)
    end
    sum(collect(1:100000000)) # some heavy work
  end
end

signal_connect(button, "clicked") do widget
  Threads.@spawn doWork()
end

```

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [August 2, 2019, 3:37pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/3 "2019-08-02T15:37:16Z")

</div>

> [@tobias.knopp](#):
>
> What is not 100% clear to me is if it is actually allowed to update the UI on the thread.

According to the [GDK manual](https://developer.gnome.org/gdk3/stable/gdk3-Threads.html), GTK+ is not thread-safe and you should call [`gdk_threads_add_idle `](https://developer.gnome.org/gdk3/stable/gdk3-Threads.html#gdk-threads-add-idle) with a callback function in order to queue GTK+ calls from another thread.

Passing C callback functions from Julia is pretty straightforward if you know what you are doing, but it might be nice if Gtk.jl made it a bit easier by adding a wrapper, as I commented at [g\_timeout\_add and other things by jonathanBieler · Pull Request #395 · JuliaGraphics/Gtk.jl · GitHub](https://github.com/JuliaGraphics/Gtk.jl/pull/395)

---

<div class="post-metadata">

### Author: ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)
#### Post date: [August 2, 2019, 4:10pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/4 "2019-08-02T16:10:24Z")

</div>

yes, then my second solution seems to be appropriate. Thanks.

---

<div class="post-metadata">

### Author: ![jonathanBieler](https://avatars.discourse-cdn.com/v4/letter/j/82dd89/32.png) [@jonathanBieler](https://discourse.julialang.org/u/jonathanBieler)
#### Post date: [August 2, 2019, 5:05pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/5 "2019-08-02T17:05:54Z")

</div>

Maybe some of the performance issues with the REPL (specially on [Windows](https://github.com/JuliaGraphics/Gtk.jl/issues/325)) could be solved, but we would need someone that understand well these problems to look at Gtk.jl core code.

---

<div class="post-metadata">

### Author: ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)
#### Post date: [August 2, 2019, 6:53pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/6 "2019-08-02T18:53:38Z")

</div>

> Maybe some of the performance issues with the REPL (specially on [Windows](https://github.com/JuliaGraphics/Gtk.jl/issues/325)) could be solved, but we would need someone that understand well these problems to look at Gtk.jl core code

Maybe that person could be the same as the one responsible for the new threading work… 🙂

---

<div class="post-metadata">

### Author: ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)
#### Post date: [August 2, 2019, 7:42pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/7 "2019-08-02T19:42:53Z")

</div>

It’s great that this works, but technically `@spawn` is not guaranteed to run on a separate thread — it’s for expressing that parallelism is available, not mandatory. I think we’ll need a different word/mechanism here. One possibility is for us to always run the event loop on a dedicated thread.

---

<div class="post-metadata">

### Author: ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)
#### Post date: [August 2, 2019, 7:53pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/8 "2019-08-02T19:53:33Z")

</div>

maybe the word `spawn` is a little bit misleading then? I would have expected that it runs the function to be threaded on a “free” thread which is not the main thread. I.e. that the thread pool is more or less an implementation detail.

---

<div class="post-metadata">

### Author: ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)
#### Post date: [August 2, 2019, 8:08pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/9 "2019-08-02T20:08:16Z")

</div>

> [@tobias.knopp](#):
>
> which is not the main thread

Yes, exactly — that would be another alternative, similar to having a dedicated event loop thread. But spawn still could not guarantee which threads tasks run on. For example given

```julia
x = 0
@spawn (while x == 0; end; fire_missiles())
@spawn x = 1

```

it’s not defined whether the missiles will be fired. Cilk has the same design consideration. And of course that example can be generalized to any number of threads. The fixed-size thread pool can’t quite be an implementation detail, for this reason. That’s why some kind of different mechanism is needed here.

---

<div class="post-metadata">

### Author: ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)
#### Post date: [August 2, 2019, 8:17pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/10 "2019-08-02T20:17:25Z")

</div>

☹ Can’t we at least prevent the spawned code to be run on the main thread? I hoped so much that `spawn` will solve this problem…

---

<div class="post-metadata">

### Author: ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)
#### Post date: [August 2, 2019, 8:24pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/11 "2019-08-02T20:24:06Z")

</div>

As I said, yes we could potentially add something like `@spawn background ...`. That handles the case where a single dedicated event/UI thread is sufficient. But what does it do when nthreads==1? It could mean that such a mode no longer exists, which might indeed be the future, but requires some thought.

---

<div class="post-metadata">

### Author: ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)
#### Post date: [August 2, 2019, 8:25pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/12 "2019-08-02T20:25:24Z")

</div>

Instead of `g_idle_add`, I think for better scalability, you’d want to do separate your value computation from the rendering (important caveat: it’s been years since I’ve actually done any “serious” GUI programming):

```julia
# application state struct
const pct_complete = Ref(0.0)
const dirty = Threads.Event()

# on work thread
while <>
    global pct_complete[] = <fraction>
    <significant_change> && notify(dirty)
end

# on main (gui) thread
while !exit
    wait(dirty)
    dirty.set = false # todo: wrap this in a function?
    # now update everything that has changed (c.f. React.js)
    p = pct_complete[]
    pb.fraction[] = p
    # sleep(0.016) -- optionally limit the update interval to 60 fps to avoid spamming Gtk with updates
end

```

Note that this assumes that updates to the state can appear asynchronously (e.g. potentially partial data updates and out-of-order) with a simple pointer update (or in this case, a Float64) assignment. If you have more complex data, you might require a lock around the data update, just so you’re aware.

---

<div class="post-metadata">

### Author: ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)
#### Post date: [August 2, 2019, 8:28pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/13 "2019-08-02T20:28:33Z")

</div>

> [@jeff.bezanson](#):
>
> But what does it do when nthreads==1

Dynamically increase the number of threads 😉

---

<div class="post-metadata">

### Author: ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)
#### Post date: [August 2, 2019, 8:32pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/14 "2019-08-02T20:32:34Z")

</div>

Ok — if we’re at the point where we can add new threads at run time and we want `@spawn background ...` then yes, I guess that could add a background thread if one doesn’t exist yet.

---

<div class="post-metadata">

### Author: ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)
#### Post date: [August 2, 2019, 8:43pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/15 "2019-08-02T20:43:58Z")

</div>

> [@jameson](#):
>
> Instead of `g_idle_add` , I think for better scalability, you’d want to do separate your value computation from the rendering (important caveat: it’s been years since I’ve actually done any “serious” GUI programming):

yes, that is an alternative, but then I would run two threads, the worker thread and some progressBar updating thread. Main thread should idle so that the user can make UI changes (i.e. cancel the operation)

---

<div class="post-metadata">

### Author: ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)
#### Post date: [August 3, 2019, 2:18pm UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/16 "2019-08-03T14:18:22Z")

</div>

The input (user control) and output (render updates) threads are required to be the same. I agree with the principle though, that you would want to ensure the input and output operations done on that thread are lightweight, and any “heavy lifting” is done in the worker thread(s).

---

<div class="post-metadata">

### Author: ![kpamnany](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kpamnany/32/206168_2.png) [@kpamnany](https://discourse.julialang.org/u/kpamnany)
#### Post date: [August 9, 2019, 12:38am UTC](https://discourse.julialang.org/t/threading-1-3-success-story/27111/17 "2019-08-09T00:38:14Z")

</div>

I have yet to page in any changes in how this is all implemented, but IIRC, `@spawn` does not yield on task creation in some situations. If there are available threads, and the spawning thread has not yielded on task creation (or shortly thereafter), then the new task will be picked up by one of the free threads. Then, so long as this new task doesn’t yield, it will continue to be run by that thread. This is functionality that is broadly useful, so if this isn’t available currently, I’ll be sure to open a PR to add it soonish.

Tobias: thanks for the post, very happy to see this in finally, and being used effectively!
