-
Notifications
You must be signed in to change notification settings - Fork 205
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
It is necessary to implement threads #333
Comments
The primary disadvantage of shared-memory concurrency is that you need to maintain a consistent memory across threads, avoid concurrent modifications and access to uninitialized or partially modified objects and provide concurrent allocation. A secondary issue is that concurrency is not supported when compiling to JavaScript. It would be nice to have some version of concurrency that is easier to use than isolates, even if it's only shared access to immutable memory or explicitly opt-in shareable memory. That's still a tough restriction for a language like Dart which has globally accessible mutable variables. |
But isn't that what service workers should be capable of? |
I can't agree more with @insinfo .
This is the case for all languages supporting threads (=pretty much all modern languages) so it shouldn't be that much of an issue. Anyway all devices are now multicores so offering the possibility to share memory between process seems essential for any language turned to be still usefull and used in the future.
To support threads into dartjs, you should probably take an approach similar to the one took by the TeaVM team to compile Java bytecode to JavaScript. They fully support the conversion of Java (and Kotlin and Scala and any language that can compile into bytecode to the JVM) Threads into Javascript by transforming them into green threads (http://teavm.org/docs/intro/overview.html) I really hope that Dart will offer a full support of threads soon (for dartvm first, it can come to dartjs latter) as this is a feature that is essential to really develop powerfull apps. |
Most of the time copying is really really cheap compared to the actual computation and shared memory isn't worth the headache. Also don't think thread synchronization comes for free! In fact, copying might not be any slower. There is also TransferableTypedData to move But if you truly need shared memory then you could use a pointer from dart:ffi. This might be a dirty trick but it absolutely works and you only have to copy the pointer address. Naturally it brings back all the problems with synchronization and you have to free the pointer manually. And in most cases it won't increase performance at all (rather the opposite). The design of Isolates isn't ineffective at all; in fact from a gc's point of view it is very effective. It also makes other things like certain compiler optimizations and memory management simpler. And it practically erradicates race conditions. Many programming languages like Erlang or Go don't share memory and pass messages, and obvioulsy they do fine. I also don't think the async features of Dart would play nice with thread synchronization. And (native system) threads wouldn't play nice with Dart's Observatory which is a very powerful tool. I would also be interested why you think working with Isolates is more painful than working with threads in any other language. For all practical purposes Isolates can be viewed as threads. The API i just as "low level" as it has to be to satisfy all use cases. But there are higher level abstractions like the pub package isolate which make dealing with Isolates much easier.
I would claim this is evidently not true. There are many languages which don't share memory and CSP libraries for C++ and Java are very popular. |
I didn't say that synchronisation comes from free but copying is not cheap. In terms of computation time, it isn't cheap when you have large data to copy (parsing a large json file and returning the result, decoding an image...) and even if the copy time might be much smaller than the computation time taken by the whole Isolate process, copying the data back to the main Isolate (=the IDE if you are on a Flutter app) might take enaugh time to have this IDE Isolate to hang on and be noticed by the end user. And in terms of memory, copying is not cheap at all as you add another copy of your data for each new Isolate. You don't have these issues with Threads that can share memory.
Do you have any example on how to use dart:ffi to share pointers between Isolates? I would be interested even if it is a dirty hack. Anyway, if any Isolate can access any data produced by other Isolates given a pointer to this data in memory, it means that Isolates already have shared memory (it is just not synchronised). So having a proper implementation of Threads in Dart would just be a matter of correctly handling synchronized access to data declared as synchronized by the developer. Isn't it? Seems like something the Dart language should offer without having to rely on dirty hacks...
Threads doesn't necessarily have to be native. Dart could choose to provide green threads in wich case Threads would work pretty much like Isolates exept that they would offer access to shared memory and ensure synchronised access to part of this memory declared as synchronised. In this case I think that Dart's Observatory would still play nicely with Dart threads. As for the async feature of Dart, languages like Python or Java have shared threads memory but also support async/await or Futures so it shouldn't be an issue.
When working with Isolates you not only have to create the send/receive ports each time you want two Isolates to be able to communicate but you also have to ensure that each data structure you want to send through the port is serialisable/deserialisable and to write a routine in the sender on how to find and send the data requested by the recever. Things can even turn a lot more complicated if you want to launch a new Isolate from another Isolate and have to broadcast data from one Isolate to another through an intermediate Isolate ports. With threads and shared memory everything is a lot more easier, you can have static synchronized repositories for your data and you would be able to access them from any Thread without the headache of asking the spawning Thread the data or passing throw the whole Thread hierarchy in case of cascade Thread calls. |
With
// main isolate
// [allocate] is in package ffi, not dart:ffi
final ptr = ffi.allocate<ffi.Uint8>();
port.send(ptr.address);
...
ffi.free(ptr);
// child isolate
port.listen((int address){
final ptr = ffi.Pointer.fromAddress(address);
}); This pointer points to shared heap memory not managed by the dart runtime but by the operating system! And allocating memory and copying list elements into it is really slow. This is a pointer you would pass as a parameter to a C function. If you free the pointer while it is used in another isolate it leads to undefined behaviour. If you don't free it it leads to a memory leak. I wouldn't recommend doing this since it isn't more memory efficient or faster. Better use
But there are issues. Synchronization involves blocking. Python has the famous
Well, not if you just use the higher level abstractions offered by the Dart team.
That might indeed be a pain point with nested data structures. But in most cases the data is serializable. As far as I know the Dart team is working on this.
To be honest, I never encountered that scenario. And I am not entirely sure I can follow. You mean that two or more child isolates spawned by a parent isolate couldn't communicate with each other? I know that a |
@lrhn About the whole compile to JS thing. Shared memory multithreading is compatible with JS, because it can compile to single threaded code. It basically won't break anything, it just won't provide any performance benefits on the web. I don't see why this should be an issue when the web will underperform other Dart runtimes anyhow. |
A feature which performs badly can be worse than no feature at all. The end result is still guidelines saying "don't use X, it's too slow", so will users not get the benefits of feature X. They'll still pay for the extra implementation overhead anyway, and the mental overhead of knowing, and then ignoring, the feature. Or, in other words, I'd rather do nothing than do something badly. |
I believe the future is WebAssembly, because soon WebAssembly will have direct access to the browser WEB APIs and will no longer need to compile for javascript. |
That indeed would work, but might not be what the developer wants or expects. If responsiveness / time to compute weren't an issue we wouldn't consider parallelism in the first place. So one could also argue that web workers should be used, though they don't use shared memory. If we really want to keep JavaScript as a compile target we also ought to have similar semantics. Though to be honest, with TypeScript and other better suited solutions out there, I don't see why we should care about this any longer. Outside of AngularDart no one uses Dart as a compile to JavaScript solution, and even AngularDart is rarely used. Just my humble opinion. |
A Huge/Mega/Collosal/Epic "pain point", in some cases I/We have to move mountains to overcome this issues that come with mandatory "serialisable" data. Besides Java for instance has built in Concurrent versions of mostly used DataTypes. I never had any issues about concurrency in Java even though I heavily used it... Qt has a similiar mechanism with signals/slots but you can transfer any Type as long as you register it AFAIK. No Limitaions... Dart IS limiting, enforcing developers to its own way of thinking, instead, it should provide me everything and let me worry about ist downsides or intricasies but do not limit me... |
@nomercy78 I agree with you
|
@nomercy78
https://api.dart.dev/stable/2.7.1/dart-isolate/SendPort/send.html
Most There have been good arguments, why system threads are not part of the platform, although they evidently work fine. That is not the point. If anybody urgently needs threads, he could pull it of by native extension. Shouldn't be too hard either. |
If dart ever look at implementing thread, they should look at java loom. Some good reading on loom. |
the dart team could at least make an extension or a separate opcional package that implements thread |
Concurrency is not a feature you can just add with a package. The Dart design is completely single-threaded, and adding support for concurrency would require adding a memory model that can handle concurrency. That's something which Dart doesn't currently have. I'd go for having a much more efficient implementation of |
@insinfo I found the following package https://pub.dev/packages/threading. |
Thumbs up for better parralelization options with Dart since the Isolate model is indeed limmiting and does not provide efficient and effective ways to benefit from multi-core CPUs. It is a trend of the recent 15 years in processor development where increased parallelism (number of cores) is the primary driver of performance growth. A typical smartphone now has 8-core CPU, AMD and Intel offer consumer products with 16 cores. Imagine a single threaded Dart program in 2025 running on a mid-range smartphone using one core out 16 available... Technically there're multiple helper threads in Dart, such as running GC, thoug they are not available to devs and don't help with code parallelism. Few remarks to the above posts:
|
I want to see native threads in Dart. There are many reasons why we would want to see native threads :
Of course, that would probably imply to modify or to adapt memory model of Dart. But AFAIK it seems necessary if Dart wants to conquest desktop application world. That would be the best improvement to the language right now. |
@johannphilippe
|
I'm actually thinking about something probably more fitted to Dart : a SharedMemory class that could be accessed from different isolates :
For example :
That is only a prototype, but such a class could solve a big part of the problem here. And still, native threads would be better to me. |
You can relatively trivially create such class using |
I don't think this is a solution and that it is efficient, there has to be a native thread implementation to be able to share Objects/Structs |
I am screaming for threads too |
On request of @mraleph and following discussion from #46754 with @gmpassos and @mkustermann , here is a proposal : This would allow the transmission of big, user-defined data across Isolates without serialization, and without The main problem with this approach is of course how to make the |
This is not new and has been cited in this thread a couple of times. |
Ack, TLDR; collapsed ones. My bad |
This is kinda mantra here :-( Yes, they asked you for use-cases and then says that there is no problem in Dart! |
Keep it civil, please. Having work-arounds is better than nothing, I'm sure it wasn't meant to dismiss your use case. The fact of the matter is that there is currently no support for threads the way many us wanted. If you want to change that, its probably best to join forces around that proposal, perhaps they can use help over there. And btw, the "whatever" in that work around can very well be Dart as well as another isolate. If you read back a bit more you'll find some more pointers how to make use of the dart:ffi interface. Of course your app's portability might suffer from this. |
Hardly that. Its simply that you specifically referenced a Flutter app as your use case and given a huge amount of functionality in Flutter already depends on interfacing with native libraries in a variety of C/C++/Java/Kotlin/ObjC/Swift it was simply pointed out that following that existing pattern, if the current functionality within Dart does not provide what you need for your specific usecase, you are free to make use of existing or new libraries written on almost any other language. |
I would love to see go channel like implementation. Simple and easy, with dart's language features it would be a killer option for writing servers. Being able to build flutter widget objects on another thread and hand it over to main is a damn good option. But object allocation and GC might be a problem, have to transfer complete ownership of objects, which is hard and dirty. Maybe third thread that just does GC could solve, but ownership transfer etc should be in place. I get why folks are slow on this. |
For (Web) servers, I'm not sure you really need this. HttpServer can bind several isolates to the same address/port so you already have multiple event-loops handling multiple incoming requests on top of async. I suppose Shelf makes use of this mechanism, I sure know Alfred does. For what it's worth, you may want to have a look at Squadron. Supports native and Web platforms, JavaScript and Web Assembly targets. Make sure you use squadron_builder to generate the code for all the plumbing. squadron_builder tries to handle as much boilerplate code as possible, but leaves serialization (primarily on Web platforms) a user-responsibility.
|
In my previous answer I mentioned a use case where it would be useful to have multi-threads with memory sharing
|
But I wasn't referring to the initial post from 2019, I was just reacting to junaid's post. |
it's about making a language generic enough to build anything with it, I mean why wouldn't you use it in servers? servers aren't just HTTP listeners, they could do lot more, why not tokenize and run llms? why to copy these tokens? There's so many things you could do if there's shared memory and as a programmer you know what you're doing. It's not a specific case of listening to sockets, servers don't end at just that. Let me give you one more example, I want to write a small database . One would argue saying run it one isolate and then make requests. But what about my db itself, if I know that certain queries in my db can be done in parallel I would choose do that, performance matters here. |
|
@junaid1460 For someone who has been using Elixir and BEAM I'm very surprised then that you don't seem to realise how similar Dart Isolates are to Erlang Processes and while Darts Isolates are missing the powerful pre-emptive scheduler, Isolates have most of the other properties of Processes and the benefits it brings to programming concurrency. Given your whole screed about needing threads, you didn't mention pre-emptive scheduling which is hardly a property of shared memory threading that has been emphasised in this thread. Feel free to peruse the talk I did that shows just how usable large numbers of Isolates with (the now not so new) Isolate groups feature are for safe, non shared memory concurrent programming with Dart. I'll leave finding the link to that talk as an exercise for you. |
No, it's just not. Erlang shares memory, it makes sharing safe by making structures immutable.
Look into how preemptive scheduler works, now think can you build it in dart. ( forget it you can't, you can but what's the point if you copy between isolates to achieve it ) See there's a difference between getting things done somehow and getting things done right, having ability fully utilise the hardware without constraints is something we're looking for here, ie: General purpose tool. |
I had already given a solid reason why we need this earlier, building a text editor. I have written it in dart, then had to move to c++, the amount of complexity in it requires me to make whole editing immutable so I can do undo/redo. Say I got the data structures that is required, I have custom piece table implementation here. But what about syntax highlighting. What about some other plugin that lets me color some weird syntax. It just can't happen in another isolate, under millisecond latency is what we are looking at here. |
Fine, shared mutable memory, but I have no idea why you make that specific point in the context of this specific issue being threads for Dart which would not be for shared immutable memory, so a rather pointless distinction in the context of this discussion.
What a bizarre thing to say! Where exactly did you see me suggest that you will be able to implement a pre-emptive scheduler in Dart yourself ?? Just like BEAM is what provides preemptive scheduling of process and not you.
Again you keep making these assertions that you can't "fully utilise the hardware" with Isolates, could you provide actual proof of this? |
I do not know how to explain it you bro, I feel like talking to a wall here. It's not what is provided and what is not. "It is ability to provide something without requiring us to do this long conversation here in this thread" Look at rust, go. They do have their own philosophy, but they do support unsafe contexts where you do whatever you want to do because some times you just need these "potentially unsafe" constructs to get the best out of the system.
Read my second comment, read lots of comments on why this is needed that has been written on this thread before this.
Again, Read my second comment, read lots of comments on why this is needed that has been written on this thread before this. if it wasn't the case this thread would not exist. |
Why is 1ms latency a hard requirement? In Flutter applications, we deal with max 16ms per frame and Isolates work for a large number of Flutter app usecases. Likewise are you aware that zero-copy for data returned from an Isolate has been available since 2.15:
Likewise as time goes on, Darts implementation Isolate performance has been improved as issues are identified and fixed. Out of interest you can see the benchmark that was posted before that issue was fixed already showed that spawning and using large numbers of short lived Isolates was already doable: 0.6ms overhead on a very old mac * again before* the issue was addressed. |
I am not your "bro"
As has been pointed out previously, this is likewise already possible in Dart with Isolates too.
I've read your comments carefully, they in no way demonstrate anything close to what you are asserting so I don't feel that replying to you further will progress this conversation in anyway and will simply spam all the other subscribers of this issue. |
Yes, if your application only does one thing, I assume whole world works like that?
Yes for sure, nobody denies it, but that has nothing to do with why we need shared memory.
Show it to me, edit one class member, in two different isolates at same time. |
Only thing I get from it is you threw some random balls at court, without knowing any crux of it and went on gaslighting the original need by saying isolates are better. |
I question the solidity of that reason. There are dozens text/code editors written in JavaScript out there. They don't need threads + mutable shared memory. |
Let's not say JS. Let's say, JS, wasm, and mainly the sorted thing is HTML and CSS. And what happens to it when you open a very large file? |
I can't really understand, why people throw random names, instead of going and building it themselves and realising how painful it is, it's very easy to throw names of things that worked on for years. They do this, that app does this, that's not really something debatable. I am telling you, build your own Rope structure or Piece buffer. When you hit save what is the logical thing you should be doing? if file is 100 megs, should you wait until file written to accept any new keystrokes ? ( Think of this in context of dart ) |
I think this issue may not be about a dispute over the technical route. |
What I said is likely wrong because I'm a novice programmer. Anyway, this issue is making me consider giving up Dart and Flutter, especially since there seem to be another options now: Kotlin and Compose Multiplatform. |
@Eglusaxie you mean just in case this thread wasn't controversial enough? 😂 |
I think opinions on this issue depend on people's understanding of how operating systems and hardware work. |
Folks please keep it respectful and on point. This absolutely not a place to bicker with each other. You are welcome to find other channels for that if that's something you wish to do in your free time. We are actively investigating different ways to open the pandora box of shared memory multithreading. You can follow the most recent variant here: #4095 |
It is necessary to implement threads, because in the majority of platforms that run Dart supports thread, such as Android, iOS, Windows, Linux, MacOS, * WebAssembly etc.
Many use cases where thread can be used easily and quickly to speed up the processing of tasks.
I use enough threads in Java Android / Linux and C #.
Threads can communicate with each other more easily than processes.
Isolated objects do not share compiled code or JavaScript objects and therefore can not share changeable data as pthreads.
Although the Isolate can provide concurrent programming behavior, it does not have the advantages of the threads, because with the threads there is shared memory and with the Isolate there is not. There are many advantages to threads over multiple processes such as lower memory consumption, another advantage of using a thread-based model is that it is fast, threads are lighter than Processes.
Another disadvantage of using a process-based model is that it will be slower. You will have to copy data between the competing parts of your program.
This does not mean that you have to abandon the Isolated Processes, but instead add another option to the most common cases where you want to accelerate an algorithm that can be easily and quickly paralleled with Threads
The text was updated successfully, but these errors were encountered: