Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run embedded compilations across multiple isolates #1981

Merged
merged 12 commits into from
Jun 6, 2023
Merged

Conversation

nex3
Copy link
Contributor

@nex3 nex3 commented May 31, 2023

lib/src/embedded/utils.dart Outdated Show resolved Hide resolved
@ntkme
Copy link
Contributor

ntkme commented Jun 2, 2023

I just tested this with my host implementation at https://github.com/ntkme/sass-embedded-host-ruby/tree/dart-sass

All tests passed. However, there is a behavior difference causing ruby process to hang after everything is finished - the problem turns out to be that after closing stdin, stdout, and stderr for the child process, the dart-sass process somehow did not exit, and ruby process was waiting for dart-sass to exit before it could exit. In the code, it got stuck here: https://github.com/ntkme/sass-embedded-host-ruby/blob/eb3e10cfaf18814663c3aac0b0cf3033a5e07d9b/lib/sass/embedded/compiler.rb#L43

This is different from the previous version where the dart-sass-embedded process would exit after stdin is closed and all inflight requests are completed.

@ntkme
Copy link
Contributor

ntkme commented Jun 2, 2023

Ruby host can be tested with:

git clone https://github.com/ntkme/sass-embedded-host-ruby.git --branch dart-sass
cd sass-embedded-host-ruby
export DART_SASS=/full/path/to/dart-sass-1.63.0-dev-macos-arm64.tar.gz
export EMBEDDED_SASS_PROTOCOL=https://github.com/sass/sass/raw/embedded-2-impl/spec/embedded_sass.proto
bundle exec rake

@nex3 nex3 marked this pull request as ready for review June 2, 2023 01:14
@nex3 nex3 requested a review from jathak June 2, 2023 01:14
@nex3
Copy link
Contributor Author

nex3 commented Jun 2, 2023

@jathak The remaining failures should be fixed once I have an embedded host PR up and running.

@nex3
Copy link
Contributor Author

nex3 commented Jun 2, 2023

@ntkme The latest commit should fix your issue.

@ntkme
Copy link
Contributor

ntkme commented Jun 2, 2023

Not very scientific benchmark result:

benchmark code
require_relative 'lib/sass-embedded'
require 'benchmark'

puts Sass.info

n = ARGV.shift.to_i
input = ARGV.shift

Benchmark.bm do |x|
  x.report('1 thread ') do
    n.times do
      Sass.compile(input).css
    end
  end

  (2..9).each do |t|
    x.report("#{t} threads") do
      tl = []
      t.times do
        tl << Thread.new do
          (n / t).times do
            Sass.compile(input).css
          end
        end
      end
      tl.each(&:join)
    end
  end

  x.report('1 compiler ') do
    n.times do
      Sass.compile(input).css
    end
  end

  (2..9).each do |t|
    compilers = Array.new(t) do
      Sass::Embedded.new
    end

    x.report("#{t} compilers") do
      tl = []
      t.times do |i|
        tl << Thread.new do
          (n / t).times do
            compilers[i].compile(input).css
          end
        end
      end
      tl.each(&:join)
    end

    compilers.each(&:close)
  end
end
tiny input
$ cat tiny.scss 
a {
  b: c;
}

$ ruby bm.rb 10000 tiny.scss
sass-embedded	1.62.1
       user     system      total        real
1 thread   0.272594   0.248071   0.520665 (  2.113635)
2 threads  0.277031   0.242044   0.519075 (  1.571126)
3 threads  0.288704   0.304601   0.593305 (  1.540196)
4 threads  0.291334   0.330008   0.621342 (  1.514646)
5 threads  0.292807   0.341196   0.634003 (  1.496866)
6 threads  0.296951   0.350379   0.647330 (  1.492878)
7 threads  0.295682   0.354896   0.650578 (  1.491245)
8 threads  0.302926   0.372139   0.675065 (  1.496665)
9 threads  0.295558   0.363906   0.659464 (  1.485602)
1 compiler   0.271272   0.238779   0.510051 (  2.088886)
2 compilers  0.286373   0.263774   0.550147 (  1.173538)
3 compilers  0.293062   0.299464   0.592526 (  0.928995)
4 compilers  0.316217   0.367282   0.683499 (  0.914765)
5 compilers  0.327091   0.369398   0.696489 (  0.913246)
6 compilers  0.328413   0.374529   0.702942 (  0.919938)
7 compilers  0.341550   0.437064   0.778614 (  0.964226)
8 compilers  0.338435   0.452326   0.790761 (  0.972465)
9 compilers  0.329214   0.398240   0.727454 (  0.973544)

$ ruby bm.rb 10000 tiny.scss
sass-embedded	1.63.0-dev
       user     system      total        real
1 thread   0.330798   0.294484   0.625282 (  2.742575)
2 threads  0.314684   0.297105   0.611789 (  1.395545)
3 threads  0.309692   0.315211   0.624903 (  1.058802)
4 threads  0.331361   0.389574   0.720935 (  1.023796)
5 threads  0.346290   0.470874   0.817164 (  1.031298)
6 threads  0.341586   0.462846   0.804432 (  1.029097)
7 threads  0.360214   0.553245   0.913459 (  1.047799)
8 threads  0.377546   0.685194   1.062740 (  1.091078)
9 threads  0.361265   0.593601   0.954866 (  1.051419)
1 compiler   0.330647   0.283865   0.614512 (  2.736968)
2 compilers  0.335977   0.319413   0.655390 (  1.499889)
3 compilers  0.342874   0.359640   0.702514 (  1.185051)
4 compilers  0.372372   0.468278   0.840650 (  1.148317)
5 compilers  0.378844   0.507014   0.885858 (  1.131671)
6 compilers  0.404797   0.634547   1.039344 (  1.170603)
7 compilers  0.407208   0.661424   1.068632 (  1.177998)
8 compilers  0.415914   0.701999   1.117913 (  1.270883)
9 compilers  0.427141   0.751592   1.178733 (  1.233394)
4kb input
$ ruby bm.rb 5000 node_modules/html-md.css/scss/html-md.scss
sass-embedded	1.62.1
       user     system      total        real
1 thread   0.185307   0.172032   0.357339 (  7.229536)
2 threads  0.190484   0.170853   0.361337 (  6.821034)
3 threads  0.201610   0.223433   0.425043 (  6.826284)
4 threads  0.206994   0.244641   0.451635 (  6.813350)
5 threads  0.210406   0.262916   0.473322 (  6.801373)
6 threads  0.214832   0.280473   0.495305 (  6.804277)
7 threads  0.217010   0.288711   0.505721 (  6.793115)
8 threads  0.224578   0.299831   0.524409 (  6.835254)
9 threads  0.219196   0.298531   0.517727 (  6.824668)
1 compiler   0.187138   0.168945   0.356083 (  7.238022)
2 compilers  0.211828   0.194989   0.406817 (  3.801163)
3 compilers  0.227247   0.237873   0.465120 (  2.633750)
4 compilers  0.239058   0.266777   0.505835 (  2.055904)
5 compilers  0.248193   0.291757   0.539950 (  1.687549)
6 compilers  0.261654   0.343289   0.604943 (  1.444759)
7 compilers  0.270278   0.388921   0.659199 (  1.298823)
8 compilers  0.310948   0.466630   0.777578 (  1.291982)
9 compilers  0.341331   0.520688   0.862019 (  1.253539)

$ ruby bm.rb 5000 node_modules/html-md.css/scss/html-md.scss
sass-embedded	1.63.0-dev
       user     system      total        real
1 thread   0.226499   0.190762   0.417261 (  7.747258)
2 threads  0.260026   0.256264   0.516290 (  4.378539)
3 threads  0.242289   0.256385   0.498674 (  2.784181)
4 threads  0.238637   0.262255   0.500892 (  2.199674)
5 threads  0.249928   0.288956   0.538884 (  1.902438)
6 threads  0.263766   0.318252   0.582018 (  1.851492)
7 threads  0.252390   0.323064   0.575454 (  1.569070)
8 threads  0.275927   0.361903   0.637830 (  1.614619)
9 threads  0.287163   0.357766   0.644929 (  1.669332)
1 compiler   0.230512   0.187318   0.417830 (  7.677505)
2 compilers  0.258404   0.253372   0.511776 (  4.210684)
3 compilers  0.257536   0.272303   0.529839 (  2.837355)
4 compilers  0.272793   0.306849   0.579642 (  2.229140)
5 compilers  0.285501   0.348988   0.634489 (  1.847132)
6 compilers  0.293154   0.389588   0.682742 (  1.563622)
7 compilers  0.310227   0.443895   0.754122 (  1.449126)
8 compilers  0.346948   0.518454   0.865402 (  1.401695)
9 compilers  0.359532   0.525065   0.884597 (  1.352259)
large input
$ ruby bm.rb 100 node_modules/bootstrap/scss/bootstrap.scss
sass-embedded	1.62.1
       user     system      total        real
1 thread   0.025360   0.022029   0.047389 ( 16.076234)
2 threads  0.024483   0.020023   0.044506 ( 16.047378)
3 threads  0.019118   0.017879   0.036997 ( 15.894161)
4 threads  0.018572   0.019898   0.038470 ( 16.047768)
5 threads  0.014649   0.016161   0.030810 ( 16.029286)
6 threads  0.015754   0.015960   0.031714 ( 15.456407)
7 threads  0.013455   0.014172   0.027627 ( 15.730440)
8 threads  0.015184   0.016719   0.031903 ( 15.390038)
9 threads  0.013614   0.014519   0.028133 ( 15.907938)
1 compiler   0.024372   0.023080   0.047452 ( 16.087168)
2 compilers  0.019418   0.025868   0.045286 (  8.303357)
3 compilers  0.019192   0.029289   0.048481 (  5.532156)
4 compilers  0.018788   0.031230   0.050018 (  4.242575)
5 compilers  0.020419   0.031347   0.051766 (  3.442458)
6 compilers  0.021702   0.032018   0.053720 (  2.794678)
7 compilers  0.020443   0.038050   0.058493 (  2.493280)
8 compilers  0.023909   0.051496   0.075405 (  2.209051)
9 compilers  0.034546   0.044739   0.079285 (  2.209131)

$ ruby bm.rb 100 ../n/_themes/sumi/node_modules/bootstrap/scss/bootstrap.scss
sass-embedded	1.63.0-dev
       user     system      total        real
1 thread   0.025996   0.022830   0.048826 ( 16.484724)
2 threads  0.021533   0.021715   0.043248 (  8.785867)
3 threads  0.021421   0.020876   0.042297 (  6.258290)
4 threads  0.021633   0.024010   0.045643 (  5.269776)
5 threads  0.019673   0.021376   0.041049 (  4.410064)
6 threads  0.019684   0.022898   0.042582 (  3.872668)
7 threads  0.018159   0.022826   0.040985 (  3.710550)
8 threads  0.019326   0.026211   0.045537 (  3.508306)
9 threads  0.028298   0.030188   0.058486 (  3.678471)
1 compiler   0.026014   0.024003   0.050017 ( 16.847493)
2 compilers  0.021814   0.031696   0.053510 (  8.508200)
3 compilers  0.021434   0.036915   0.058349 (  5.660580)
4 compilers  0.021437   0.035256   0.056693 (  4.338396)
5 compilers  0.024538   0.046578   0.071116 (  3.533973)
6 compilers  0.021746   0.042238   0.063984 (  2.867095)
7 compilers  0.023591   0.040820   0.064411 (  2.656477)
8 compilers  0.024856   0.040132   0.064988 (  2.265965)
9 compilers  0.035693   0.046084   0.081777 (  2.300096)

@ntkme
Copy link
Contributor

ntkme commented Jun 2, 2023

Another benchmark with high round trips

benchmark code
require_relative 'lib/sass-embedded'
require 'benchmark'

puts Sass.info

n = ARGV.shift.to_i
rt = ARGV.shift

input = '
@for $i from 1 through ' + rt + ' {
  ul:nth-child(#{$i}) {
    content: foo($i);
  }
}
'

functions = {
  'foo($i)': lambda do |*|
    Sass::Value::String.new('foo')
  end
}

Benchmark.bm do |x|
  x.report('1 thread ') do
    n.times do
      Sass.compile_string(input, functions: functions).css
    end
  end

  (2..9).each do |t|
    x.report("#{t} threads") do
      tl = []
      t.times do
        tl << Thread.new do
          (n / t).times do
            Sass.compile_string(input, functions: functions).css
          end
        end
      end
      tl.each(&:join)
    end
  end

  x.report('1 compiler ') do
    n.times do
      Sass.compile_string(input, functions: functions).css
    end
  end

  (2..9).each do |t|
    compilers = Array.new(t) do
      Sass::Embedded.new
    end

    x.report("#{t} compilers") do
      tl = []
      t.times do |i|
        tl << Thread.new do
          (n / t).times do
            compilers[i].compile_string(input, functions: functions).css
          end
        end
      end
      tl.each(&:join)
    end

    compilers.each(&:close)
  end
end
10 function call requests per compilation
$ ruby fn.rb 5000 10
sass-embedded	1.62.1
       user     system      total        real
1 thread   1.437286   0.591179   2.028465 (  4.452346)
2 threads  1.456174   0.604267   2.060441 (  4.134608)
3 threads  1.445890   0.596221   2.042111 (  4.141824)
4 threads  1.444768   0.598736   2.043504 (  4.159393)
5 threads  1.468726   0.604880   2.073606 (  4.148431)
6 threads  1.438693   0.599903   2.038596 (  4.112744)
7 threads  1.458637   0.602838   2.061475 (  4.154551)
8 threads  1.463123   0.601480   2.064603 (  4.147112)
9 threads  1.444087   0.601121   2.045208 (  4.118825)
1 compiler   1.439845   0.575228   2.015073 (  4.406776)
2 compilers  1.574018   1.022398   2.596416 (  3.143335)
3 compilers  1.743066   1.594490   3.337556 (  3.294284)
4 compilers  1.769220   1.652304   3.421524 (  3.297496)
5 compilers  1.732356   1.507222   3.239578 (  3.360922)
6 compilers  1.713466   1.442498   3.155964 (  3.202339)
7 compilers  1.692406   1.321548   3.013954 (  3.141088)
8 compilers  1.699383   1.339543   3.038926 (  3.177287)
9 compilers  1.713104   1.247489   2.960593 (  3.224177)

$ ruby fn.rb 5000 10
sass-embedded	1.63.0-dev
       user     system      total        real
1 thread   1.619493   0.557843   2.177336 (  5.807820)
2 threads  1.613214   0.920729   2.533943 (  3.747099)
3 threads  1.696295   1.326228   3.022523 (  3.481165)
4 threads  1.735137   1.432016   3.167153 (  3.395798)
5 threads  1.733791   1.418463   3.152254 (  3.327151)
6 threads  1.710477   1.377294   3.087771 (  3.256467)
7 threads  1.713756   1.355611   3.069367 (  3.246084)
8 threads  1.696299   1.346463   3.042762 (  3.199390)
9 threads  1.700897   1.356143   3.057040 (  3.207827)
1 compiler   1.640098   0.556481   2.196579 (  5.874863)
2 compilers  1.702511   1.118924   2.821435 (  4.047045)
3 compilers  1.877241   1.707119   3.584360 (  3.972829)
4 compilers  1.930236   1.776362   3.706598 (  3.897902)
5 compilers  1.936294   1.672640   3.608934 (  3.872829)
6 compilers  1.939381   1.636888   3.576269 (  3.889480)
7 compilers  1.883850   1.488630   3.372480 (  3.761807)
8 compilers  1.877362   1.460496   3.337858 (  3.770611)
9 compilers  1.884453   1.374360   3.258813 (  3.831859)

@nex3
Copy link
Contributor Author

nex3 commented Jun 2, 2023

Am I interpreting those results correctly to indicate that this is almost universally slower than the previous version, even when making heavy use of parallelism?

@ntkme
Copy link
Contributor

ntkme commented Jun 2, 2023

The x-threads test means using a single persisted compiler that each runs x-threads (if supported).
The x-compilers test means using x persisted compiler that each runs 1 thread.

We are always slower when using 1 persisted compiler with 1 thread in new version comparing to old version. - This is expected due to isolate overhead.
When using 1 persisted compiler with x threads, this is significantly faster in new version due to parallelism, almost as fast as x compilers each with 1 thread in previous version. - This is also expected.
Using x number of persisted compiler each with 1 thread in previous version is always fastest. - I think this is also somewhat expected.

@nex3
Copy link
Contributor Author

nex3 commented Jun 2, 2023

Oh I see, I missed the "X threads" readout. In that case, given that the additional single-threaded overhead is relatively low, I think it's acceptable.

There are some further possibilities for improvement here. In dart-lang/sdk#52577 I'm asking the Dart team for better ways to limit copies when sending messages across isolates. We could also look into making the compiler able to switch between parallel and serial modes—either with an explicit switch from the caller, or by detecting when the caller attempts to run multiple compilations at once and switching modes after the active compilation finishes.

@ntkme
Copy link
Contributor

ntkme commented Jun 3, 2023

We could also look into making the compiler able to switch between parallel and serial modes—either with an explicit switch from the caller, or by detecting when the caller attempts to run multiple compilations at once and switching modes after the active compilation finishes.

Or we can introduce a command line flag like --concurrency=X for setting the pool size (default to 1). When concurrency=1 it can run serial mode in main isolate. After all concurrent isolates only benefit performance if host actually support submitting multiple requests concurrently to the same persisted compiler.

@nex3
Copy link
Contributor Author

nex3 commented Jun 3, 2023

That's definitely another option, although all things being equal I think it'd probably be better to avoid punting the decision about when/whether to be parallel to the host. After all, even if the host can submit parallel requests, it's not always going to be called in a way that causes them.

@ntkme
Copy link
Contributor

ntkme commented Jun 4, 2023

I just change the way threading works on the ruby host side. Performance of 1.63.0-dev has greatly improved in all cases comparing to the previous result of 1.63.0-dev.

Specifically, now multi-threading is consistently faster than multi-processes for lots of tiny input/output, and getting closer to multi-processes for large input/output.

$ ruby bm.rb 10000 tiny.scss
sass-embedded	1.63.0-dev
       user     system      total        real
1 thread   0.264298   0.221971   0.486269 (  2.316187)
2 threads  0.312205   0.280659   0.592864 (  1.512835)
3 threads  0.320694   0.325861   0.646555 (  1.144536)
4 threads  0.323114   0.375509   0.698623 (  0.980210)
5 threads  0.339161   0.452541   0.791702 (  0.948369)
6 threads  0.354084   0.536381   0.890465 (  0.951802)
7 threads  0.365786   0.588507   0.954293 (  0.965197)
8 threads  0.357598   0.581409   0.939007 (  0.937596)
9 threads  0.368075   0.625848   0.993923 (  0.954122)
1 compiler   0.265905   0.214685   0.480590 (  2.319748)
2 compilers  0.325518   0.301101   0.626619 (  1.582841)
3 compilers  0.343837   0.373367   0.717204 (  1.211886)
4 compilers  0.358936   0.469844   0.828780 (  1.056833)
5 compilers  0.394540   0.651390   1.045930 (  1.062241)
6 compilers  0.427540   0.812276   1.239816 (  1.101767)
7 compilers  0.431454   0.877821   1.309275 (  1.104671)
8 compilers  0.431377   0.862028   1.293405 (  1.088816)
9 compilers  0.431339   0.827432   1.258771 (  1.074677)

$ ruby bm.rb 5000 node_modules/html-md.css/scss/html-md.scss
sass-embedded	1.63.0-dev
       user     system      total        real
1 thread   0.171362   0.159851   0.331213 (  7.118186)
2 threads  0.178942   0.135584   0.314526 (  3.880564)
3 threads  0.202082   0.171308   0.373390 (  2.684508)
4 threads  0.205692   0.184321   0.390013 (  2.118297)
5 threads  0.209465   0.196086   0.405551 (  1.792228)
6 threads  0.212231   0.202058   0.414289 (  1.599602)
7 threads  0.223914   0.223093   0.447007 (  1.492282)
8 threads  0.250601   0.290655   0.541256 (  1.493784)
9 threads  0.309676   0.377532   0.687208 (  1.489101)
1 compiler   0.181377   0.154158   0.335535 (  7.084509)
2 compilers  0.201146   0.151580   0.352726 (  3.857460)
3 compilers  0.226206   0.195393   0.421599 (  2.745819)
4 compilers  0.233027   0.215457   0.448484 (  2.120524)
5 compilers  0.244632   0.237774   0.482406 (  1.741412)
6 compilers  0.253624   0.252395   0.506019 (  1.482015)
7 compilers  0.272989   0.298893   0.571882 (  1.339119)
8 compilers  0.307536   0.369097   0.676633 (  1.290792)
9 compilers  0.334171   0.434355   0.768526 (  1.253083)

$ ruby bm.rb 100 node_modules/bootstrap/scss/bootstrap.scss
sass-embedded	1.63.0-dev
       user     system      total        real
1 thread   0.023954   0.020410   0.044364 ( 15.636842)
2 threads  0.021138   0.018343   0.039481 (  8.498342)
3 threads  0.021299   0.017797   0.039096 (  6.171960)
4 threads  0.021377   0.021060   0.042437 (  5.015492)
5 threads  0.020323   0.016739   0.037062 (  4.388836)
6 threads  0.020563   0.019233   0.039796 (  3.871104)
7 threads  0.017799   0.018139   0.035938 (  3.631320)
8 threads  0.020402   0.023304   0.043706 (  3.368685)
9 threads  0.035081   0.034290   0.069371 (  3.697794)
1 compiler   0.021968   0.018992   0.040960 ( 15.496894)
2 compilers  0.019599   0.023470   0.043069 (  8.156582)
3 compilers  0.018196   0.022673   0.040869 (  5.601265)
4 compilers  0.020514   0.023555   0.044069 (  4.267264)
5 compilers  0.021096   0.028183   0.049279 (  3.449012)
6 compilers  0.018175   0.024143   0.042318 (  2.787782)
7 compilers  0.019818   0.033567   0.053385 (  2.509613)
8 compilers  0.022188   0.042540   0.064728 (  2.203185)
9 compilers  0.040204   0.042929   0.083133 (  2.203417)

@ntkme
Copy link
Contributor

ntkme commented Jun 5, 2023

What's interesting is that offloading the protobuf decoding from the dispatcher I/O thread on the ruby host side improved the single compiler single thread performance so much for medium and large size input/output, for which it makes up for the isolate overhead and becomes faster overall. For tiny input/output test with single compiler single thread, it was slower but only 0.02ms per compilation on average.

So from ruby host perspective, this is a win. It would get even better with future improvement on reducing dart isolate communication overhead.

$ ruby bm.rb 10000 tiny.scss
sass-embedded	1.62.1
       user     system      total        real
1 thread   0.272594   0.248071   0.520665 (  2.113635)

$ ruby bm.rb 10000 tiny.scss
sass-embedded	1.63.0-dev
       user     system      total        real
1 thread   0.264298   0.221971   0.486269 (  2.316187)

$ ruby bm.rb 5000 node_modules/html-md.css/scss/html-md.scss
sass-embedded	1.62.1
       user     system      total        real
1 thread   0.185307   0.172032   0.357339 (  7.229536)

$ ruby bm.rb 5000 node_modules/html-md.css/scss/html-md.scss
sass-embedded	1.63.0-dev
       user     system      total        real
1 thread   0.171362   0.159851   0.331213 (  7.118186)

$ ruby bm.rb 100 node_modules/bootstrap/scss/bootstrap.scss
sass-embedded	1.62.1
       user     system      total        real
1 thread   0.025360   0.022029   0.047389 ( 16.076234)

$ ruby bm.rb 100 node_modules/bootstrap/scss/bootstrap.scss
sass-embedded	1.63.0-dev
       user     system      total        real
1 thread   0.023954   0.020410   0.044364 ( 15.636842)

@ntkme
Copy link
Contributor

ntkme commented Jun 5, 2023

Sorry never mind with my previous comment, my local branch state was not synced correctly. The compiler does appear to shutdown correctly.

@nex3 nex3 merged commit a88318f into main Jun 6, 2023
45 checks passed
@nex3 nex3 deleted the embedded-protocol-2 branch June 6, 2023 21:23
jgerigmeyer added a commit to oddbird/dart-sass that referenced this pull request Jun 7, 2023
* main:
  Run embedded compilations across multiple isolates (sass#1981)
jgerigmeyer added a commit to oddbird/dart-sass that referenced this pull request Jun 7, 2023
* main:
  Release 1.63.0 (sass#1987)
  Run embedded compilations across multiple isolates (sass#1981)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement Embedded Protocol 2 Concurrent requests block each other and Stack Overflow under high concurrency
3 participants