# Parallel assembly of a finite element sparse matrix

**URL:** <https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947>\
**Category:** General Usage\
**Tags:** parallel\
**Created:** [March 12, 2023, 2:11am UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947 "2023-03-12T02:11:37Z")\
**Posts on this page:** 15\
**Page:** 2

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [March 16, 2023, 7:14pm UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/21 "2023-03-16T19:14:34Z")

</div>

Yes, in this case. It could be the number of cores…

---

<div class="post-metadata">

**Author:** ![purplishrock](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/purplishrock/32/13451_2.png) [@purplishrock](https://discourse.julialang.org/u/purplishrock)\
**Post date:** [March 16, 2023, 8:54pm UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/22 "2023-03-16T20:54:23Z")

</div>

Well the XEON does have 8 cores, so … you think it would be good up to 7 😉

Really interesting data points that you have provided. I really like to see these kind of metrics in the Julia forum !

edit: math is hard. 2x xeon = 16. so 1 for windows, and 1 for the virus scanner in windows leaves 14

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [March 17, 2023, 3:11am UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/23 "2023-03-17T03:11:37Z")

</div>

Actually, each of the sockets has 8 cores. 16 in total then. I don’t have an explanation for the poor performance.

---

<div class="post-metadata">

**Author:** ![termi-official](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/termi-official/32/47815_2.png) [@termi-official](https://discourse.julialang.org/u/termi-official)\
**Post date:** [March 17, 2023, 1:49pm UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/24 "2023-03-17T13:49:21Z")

</div>

Thanks for investigating this issue further Prof. Krysl. Sorry, I could not find time to come back to the issue linked by Kristoffer yet (but I still follow the thread). From a performance perspective the assembly on a single thread is more or less compute bound. Parallelizing assembly with a low number of threads should not be a big issue (with sufficient memory bandwidth and cache). However, with more threads you increase the pressure on all memory lanes. Here I still think it is a mixture of cache/bandwidth issues (i.e. bad or even conflicting cache access patterns+memory bus cannot keep up with the CPUs read/write access) and frequency boosting (i.e. at lower total load each core has higher frequency). Fore some discussion I highly recommend the WorkStream paper ([dx.doi.org/10.1145/2851488](http://dx.doi.org/10.1145/2851488)), because we basically reproduce Figure 4 from this paper. However, take this with a grain of salt, as I still have to confirm everything in more detailed benchmarks.

Another relevant thread is [How to achieve perfect scaling with Threads (Julia 1.7.1) - #10 by carstenbauer](https://discourse.julialang.org/t/how-to-achieve-perfect-scaling-with-threads-julia-1-7-1/92603/10) which discusses some of the mentioned problems in more detail.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [March 17, 2023, 3:29pm UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/25 "2023-03-17T15:29:57Z")

</div>

![image](https://global.discourse-cdn.com/julialang/original/3X/2/4/244051b735893b0e0e4073b42765e853ba3cc883.png)  
The machine Firenze with Windows 10 Julia 1.8.5.  
Better speed ups than the WSL2 setup.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [March 17, 2023, 3:55pm UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/26 "2023-03-17T15:55:24Z")

</div>

Also, I think I solved the problem with the tasks: I think I need to start (N+1) threads in order to have N tasks. Apparently, one thread needs to be the main to carry the spine of the computation. If I do this, the tasks finish in more or less the same time (there is still a bit of variation, on the order of 10 %, but nothing like the huge differences between fast and slow tasks before).

This is the speed up of Firenze/Windows 10/with tasks.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/5/4/547358dc1f1542d806057100e8fa50f8d91a2cf8.png)

Edit: The tasks take about 0.03 sec to start and another 0.03 seconds to spawn. So that can add up.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [March 17, 2023, 5:03pm UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/27 "2023-03-17T17:03:00Z")

</div>

Alas, I spoke to soon. No, the problem of the slow tasks still not solved. On the Horntail, even starting N+1 (or even N+8) threads for N tasks, some of the tasks are still delayed by a significant factor (100-200%) relative to others.

How do I debug this?

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [February 10, 2024, 1:13am UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/28 "2024-02-10T01:13:30Z")

</div>

I see similar irregularities in the task time consumed (some tasks, a random number of them, will take much longer than others, often double the time) on Apple Mac M2 Ultra.

```julia
Julia Version 1.10.0
Commit 3120989f39b (2023-12-25 18:01 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: macOS (arm64-apple-darwin22.4.0)
  CPU: 24 × Apple M2 Ultra
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, apple-m1)
  Threads: 1 on 16 virtual cores

```

I don’t know what it is, but I suspect task scheduling. An issue has been filed,

> <https://github.com/JuliaLang/julia/issues/53269>
>
> \`\`\`
> Julia Version 1.10.0
> Commit 3120989f39b (2023-12-25 18:01 UTC)
> Build Info…:
> Official https://julialang.org/ release
> Platform Info:
> OS: macOS (arm64-apple-darwin22.4.0)
> CPU: 24 × Apple M2 Ultra
> WORD\_SIZE: 64
> LIBM: libopenlibm
> LLVM: libLLVM-15.0.7 (ORCJIT, apple-m1)
> Threads: 1 on 16 virtual cores
> \`\`\`
> This batch file is run on an unloaded machine (single user):
> \`\`\`
> if !isdir("FinEtoolsHeatDiff.jl")
> run(\`git clone https://github.com/PetrKryslUCSD/FinEtoolsHeatDiff.jl.git\`)
> end
> using Pkg
> cd("FinEtoolsHeatDiff.jl/examples")
> println("Current folder: $(pwd())")
> Pkg.activate(".")
> Pkg.instantiate()
> Pkg.update()
> @show Threads.nthreads()
> include(joinpath(pwd(), "steady\_state/3-d/Poisson\_examples.jl"))
> using .Main.Poisson\_examples; Main.Poisson\_examples.Poisson\_FE\_H20\_parass\_tasks\_example(100)
> using .Main.Poisson\_examples; Main.Poisson\_examples.Poisson\_FE\_H20\_parass\_tasks\_example(100)
> \`\`\`
> As shown in the batch file, a computation is run twice with the same parameters:
> \`\`\`
> pkrysl@samadira exp % ~/julia-1.10.0/bin/julia -t 17 batch.jl
> Current folder: /Users/pkrysl/exp/FinEtoolsHeatDiff.jl/examples
> Activating project at \`~/exp/FinEtoolsHeatDiff.jl/examples\`
> Updating registry at \`~/.julia/registries/General.toml\`
> Updating git-repo \`https://github.com/PetrKryslUCSD/Targe2.jl.git\`
> No Changes to \`~/exp/FinEtoolsHeatDiff.jl/examples/Project.toml\`
> No Changes to \`~/exp/FinEtoolsHeatDiff.jl/examples/Manifest.toml\`
> Threads.nthreads() = 17
> \[ Info: All examples may be executed with
> using .Main.Poisson\_examples; Main.Poisson\_examples.allrun()
> \[ Info: Starting \<\<\<\<\<\<\<\<\<\<\<\<\<\<\<\<\<\< FIRST RUN
> \[ Info: 1000000 elements
> \[ Info: Number of free degrees of freedom: 3910599
> \[ Info: Conductivity: serial
> \[ Info: Conductivity done serial 19.16116690635681
> \[ Info: All done serial 21.8343768119812
> \[ Info: Conductivity: parallel
> \[ Info: 1: Started 0.03969597816467285
> \[ Info: 1: Spawned 0.09760499000549316
> \[ Info: 2: Started 0.09940600395202637
> \[ Info: 3: Started 0.09951305389404297
> \[ Info: 2: Spawned 0.0995330810546875
> \[ Info: 4: Started 0.09955406188964844
> \[ Info: 5: Started 0.09959006309509277
> \[ Info: 3: Spawned 0.09958100318908691
> \[ Info: 6: Started 0.09961915016174316
> \[ Info: 5: Spawned 0.09964394569396973
> \[ Info: 4: Spawned 0.09963512420654297
> \[ Info: 6: Spawned 0.09971213340759277
> \[ Info: 7: Started 0.09971809387207031
> \[ Info: 8: Started 0.09978413581848145
> \[ Info: 8: Spawned 0.09986209869384766
> \[ Info: 7: Spawned 0.09983396530151367
> \[ Info: 9: Started 0.0999000072479248
> \[ Info: 10: Started 0.09997797012329102
> \[ Info: 9: Spawned 0.10000205039978027
> \[ Info: 10: Spawned 0.10006904602050781
> \[ Info: 11: Started 0.10009407997131348
> \[ Info: 12: Started 0.1001901626586914
> \[ Info: 11: Spawned 0.10021495819091797
> \[ Info: 12: Spawned 0.1002650260925293
> \[ Info: 13: Started 0.10025405883789062
> \[ Info: 14: Started 0.10038900375366211
> \[ Info: 13: Spawned 0.10040903091430664
> \[ Info: 14: Spawned 0.10048103332519531
> \[ Info: 15: Started 0.10048699378967285
> \[ Info: 16: Started 0.10061907768249512
> \[ Info: 16: Spawned 0.10070610046386719
> \[ Info: 15: Spawned 0.10070610046386719
> \[ Info: 1: Started conductivity 0.29084300994873047
> \[ Info: 6: Started conductivity 0.30785512924194336
> \[ Info: 2: Started conductivity 0.31269001960754395
> \[ Info: 8: Started conductivity 0.31369996070861816
> \[ Info: 10: Started conductivity 0.3148770332336426
> \[ Info: 11: Started conductivity 0.3154640197753906
> \[ Info: 3: Started conductivity 0.3155040740966797
> \[ Info: 4: Started conductivity 0.31554698944091797
> \[ Info: 7: Started conductivity 0.3156399726867676
> \[ Info: 14: Started conductivity 0.3165130615234375
> \[ Info: 5: Started conductivity 0.3165619373321533
> \[ Info: 9: Started conductivity 0.3167459964752197
> \[ Info: 12: Started conductivity 0.31691908836364746
> \[ Info: 13: Started conductivity 0.3172330856323242
> \[ Info: 16: Started conductivity 0.3172590732574463
> \[ Info: 15: Started conductivity 0.3174870014190674
> \[ Info: 6: Finished 1.7215111255645752 \<\<\<\<\<\<\<\<\<\<\<\< ALL TASKS FINISH
> \[ Info: 2: Finished 1.7214860916137695
> \[ Info: 7: Finished 1.7238011360168457
> \[ Info: 3: Finished 1.7238130569458008
> \[ Info: 1: Finished 1.723978042602539
> \[ Info: 16: Finished 1.7248311042785645
> \[ Info: 13: Finished 1.7270441055297852
> \[ Info: 8: Finished 1.7272679805755615
> \[ Info: 14: Finished 1.729992151260376
> \[ Info: 4: Finished 1.7307720184326172
> \[ Info: 5: Finished 1.7324531078338623
> \[ Info: 9: Finished 1.7324731349945068
> \[ Info: 10: Finished 1.7330989837646484
> \[ Info: 11: Finished 1.733449935913086
> \[ Info: 15: Finished 1.7334620952606201
> \[ Info: 12: Finished 1.7362711429595947 \<\<\<\<\<\<\<\<\<\<\< IN ROUGHLY THE SAME TIME
> \[ Info: Started make-matrix 1.7365190982818604
> \[ Info: All done 1.743549108505249
> \[ Info: Short-circuited exit
> \[ Info: Starting \<\<\<\<\<\<\<\<\<\<\<\<\<\<\<\<\< SECOND RUN
> \[ Info: 1000000 elements
> \[ Info: Number of free degrees of freedom: 3910599
> \[ Info: Conductivity: serial
> \[ Info: Conductivity done serial 18.674499034881592
> \[ Info: All done serial 21.335928916931152
> \[ Info: Conductivity: parallel
> \[ Info: 1: Started 0.02824687957763672
> \[ Info: 2: Started 0.02838897705078125
> \[ Info: 1: Spawned 0.02837681770324707
> \[ Info: 2: Spawned 0.028560876846313477
> \[ Info: 3: Started 0.028569936752319336
> \[ Info: 3: Spawned 0.028743982315063477
> \[ Info: 4: Started 0.028760910034179688
> \[ Info: 5: Started 0.028944015502929688
> \[ Info: 4: Spawned 0.028958797454833984
> \[ Info: 6: Started 0.029123783111572266
> \[ Info: 5: Spawned 0.029111862182617188
> \[ Info: 7: Started 0.029152870178222656
> \[ Info: 6: Spawned 0.029179811477661133
> \[ Info: 8: Started 0.02931690216064453
> \[ Info: 7: Spawned 0.02931690216064453
> \[ Info: 8: Spawned 0.029472827911376953
> \[ Info: 9: Started 0.029507875442504883
> \[ Info: 10: Started 0.029678821563720703
> \[ Info: 9: Spawned 0.029706954956054688
> \[ Info: 11: Started 0.029832839965820312
> \[ Info: 12: Started 0.029864788055419922
> \[ Info: 10: Spawned 0.029883861541748047
> \[ Info: 11: Spawned 0.029930830001831055
> \[ Info: 13: Started 0.030006885528564453
> \[ Info: 14: Started 0.030041933059692383
> \[ Info: 13: Spawned 0.030104875564575195
> \[ Info: 12: Spawned 0.030069828033447266
> \[ Info: 15: Started 0.030176877975463867
> \[ Info: 16: Started 0.030210018157958984
> \[ Info: 16: Spawned 0.03033900260925293
> \[ Info: 14: Spawned 0.030319929122924805
> \[ Info: 15: Spawned 0.030336856842041016
> \[ Info: 13: Started conductivity 0.09562182426452637
> \[ Info: 9: Started conductivity 0.09810400009155273
> \[ Info: 2: Started conductivity 0.1115868091583252
> \[ Info: 1: Started conductivity 0.12673091888427734
> \[ Info: 3: Started conductivity 0.12754082679748535
> \[ Info: 7: Started conductivity 0.12888884544372559
> \[ Info: 10: Started conductivity 0.12903380393981934
> \[ Info: 11: Started conductivity 0.1291518211364746
> \[ Info: 5: Started conductivity 0.12967586517333984
> \[ Info: 6: Started conductivity 0.1297318935394287
> \[ Info: 4: Started conductivity 0.12999987602233887
> \[ Info: 12: Started conductivity 0.1302487850189209
> \[ Info: 16: Started conductivity 0.13028287887573242
> \[ Info: 8: Started conductivity 0.13030695915222168
> \[ Info: 15: Started conductivity 0.15201091766357422
> \[ Info: 14: Started conductivity 0.162139892578125
> \[ Info: 12: Finished 1.3724877834320068
> \[ Info: 1: Finished 1.372588872909546
> \[ Info: 3: Finished 1.4589488506317139
> \[ Info: 5: Finished 1.4598939418792725
> \[ Info: 2: Finished 1.4610848426818848
> \[ Info: 11: Finished 1.4626657962799072
> \[ Info: 7: Finished 1.4626657962799072
> \[ Info: 13: Finished 1.4634709358215332
> \[ Info: 10: Finished 1.4653029441833496
> \[ Info: 16: Finished 1.4664249420166016
> \[ Info: 6: Finished 1.4673268795013428
> \[ Info: 9: Finished 1.468505859375
> \[ Info: 4: Finished 1.4687118530273438
> \[ Info: 14: Finished 2.7745578289031982 \<\<\<\<\<\<\<\<\<\<\<\<\<\<\<\< THESE FINISH in double the time as the others
> \[ Info: 15: Finished 2.776059865951538 \<\<\<\<\<\<\<\<\<\<\<\<\<\<\<\<
> \[ Info: 8: Finished 2.776533842086792 \<\<\<\<\<\<\<\<\<\<\<\<\<\<\<\<
> \[ Info: Started make-matrix 2.776829957962036
> \[ Info: All done 2.7807087898254395
> \[ Info: Short-circuited exit
> pkrysl@samadira exp %
> \`\`\`
> So, some tasks take practically double the time of the others. The number of tasks that takes longer varies from run to run.

---

<div class="post-metadata">

**Author:** ![Domenico\_Lahaye](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/domenico_lahaye/32/203728_2.png) [@Domenico\_Lahaye](https://discourse.julialang.org/u/Domenico_Lahaye)\
**Post date:** [February 10, 2024, 7:05am UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/29 "2024-02-10T07:05:22Z")

</div>

Greetings. Much like your work. Is sparse matrix assembly still running in parallel here?

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [February 10, 2024, 7:22am UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/30 "2024-02-10T07:22:21Z")

</div>

> [@PetrKryslUCSD](#):
>
> I implemented an alternative way based on threads.

Just to be clear here and to avoid potential confusion, your `@threads` based implementation also creates tasks under the hood. Roughly speaking `@threads` is the same as dividing the iteration interval into `nthreads()` parts and then `@spawn`ing a task per chunk (i.e. one thread runs one task corresponding to one chunk).

AFAICS, you’re trying to do the same in your “task variant”, i.e. chunking with `chunks` and `@spawn`ing the tasks manually.

Am I understanding correctly, that the “thread variant” behaves correctly but the “task variant” is not? Given the above, if you see (vastly) different behavior between the two variants, you should check what you’re doing differently in both cases. For example, you seem to be running (i.e. allocating)

`_a = _task_local_assembler(a, b)`

on each task in the “task variant” but outside of the `@threads` loop in the “threads variant”.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [February 10, 2024, 2:34pm UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/31 "2024-02-10T14:34:52Z")

</div>

Yes, indeed. There are two implementations here task-based and threads-based.

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [February 10, 2024, 3:03pm UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/32 "2024-02-10T15:03:51Z")

</div>

> [@PetrKryslUCSD](#):
>
> There are two implementations here task-based and threads-based.

At the risk of coming off as nitpicky (but to be more precise for beginners who might be reading this): Both implementations are creating tasks which then run on multiple threads. Hence, they are both “task-based” and “threads-based”.  
What is (likely) meant here is that one implementation uses `@spawn` whereas the other uses `@threads`.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [February 10, 2024, 3:13pm UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/33 "2024-02-10T15:13:09Z")

</div>

Thank you for honing my description (nitpicky is good!). It is as you describe.  
In the “spawn” case I create the tasks explicitly, whereas “threads” do whatever it is they do under the hood to process their chunks.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [February 11, 2024, 12:02am UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/34 "2024-02-11T00:02:25Z")

</div>

It would seem I found a possible reason why the tasks are sometimes delayed, and also a possible solution: [Tasks with the same workloads sometimes finish in much longer time than others · Issue #53269 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/53269#issuecomment-1937084122)

The parallel speedups on the Mac M2 Ultra of the assembly with 2, 4, 8, and 16 assembly tasks for an 8-million finite elements mesh:  
2: 1.9, 4: 3.49, 8: 6.53, 16: 11.08.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [February 28, 2024, 5:04am UTC](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947/35 "2024-02-28T05:04:02Z")

</div>

Problem solved: [Threaded Assembly Performance Degradation · Issue #526 · Ferrite-FEM/Ferrite.jl · GitHub](https://github.com/Ferrite-FEM/Ferrite.jl/issues/526#issuecomment-1958435053)

General parallel assembly now available in FinEtools.jl. Script to test it: [Threaded Assembly Performance Degradation · Issue #526 · Ferrite-FEM/Ferrite.jl · GitHub](https://github.com/Ferrite-FEM/Ferrite.jl/issues/526#issuecomment-1953025723)

[Previous page](https://discourse.julialang.org/t/parallel-assembly-of-a-finite-element-sparse-matrix/95947.md?page=1)
