[HN Gopher] Elixir and Rust is a good mix ___________________________________________________________________ Elixir and Rust is a good mix Author : rio517 Score : 196 points Date : 2023-04-13 18:29 UTC (4 hours ago) (HTM) web link (fly.io) (TXT) w3m dump (fly.io) | mrmincent wrote: | I made the 'risky' decision to learn Elixir & Phoenix for a 6 | week University project that I delivered earlier this week. It | could have turned out to be a terrible decision but honestly once | I got my head around it, it's probably some of the most | productive coding sessions I've ever had. Deploying to Fly.io was | also amazing, I think it was 3-5 commands from signup to deployed | with a database. Very happy with it all. | alberth wrote: | Doesn't the use of Rust have to be extremely minimal because | ErlangVM has hard time limits on their preemptive scheduler and | if your Rust code hasn't finished when preempted, that causes | lots of problems. | | EDIT: thanks for pointing out where in the article this is talked | about. | peregrine wrote: | I go into this in the article :) the rustler team has a made a | DirtyNif that can work around that, or you can manually yield | if you'd like. | clessg wrote: | Indeed, your (excellent) article addresses this, here's the | gist for those following along: | | > Change `#[rustler::nif]` to `#[rustler::nif(schedule = | "DirtyCpu")]` | | > This tells the Rustler and BEAM to automagically schedule | this in a way that won't block the entire world while it | works. Again amazing, this is called a DirtyNif and is way | more difficult to work with when you are manually using this | via C. | | Essentially, regular NIFs have to be extremely fast (< 1ms) | because the VM can't preempt them - they run on the same | scheduler threads the BEAM itself uses. Dirty NIFs solve this | by running jobs in a completely separate thread pool ("dirty | schedulers"). Rustler's docs explain it succinctly | (https://docs.rs/rustler/latest/rustler/attr.nif.html): | | > For functions that may take some time to return - let's say | more than 1 millisecond - it is recommended to use the | `schedule` flag. This tells the BEAM to allocate that NIF | call to a special scheduler. These special schedulers are | called "dirty" schedulers. | | > We can have two types of "lengthy work" functions: those | that are CPU intensive and those that are IO intensive. They | should be flagged with "DirtyCpu" and "DirtyIo", | respectively. | | (Somewhat OT, but since I'm here: excellent article @ | peregrine! I _really_ enjoyed the read. Elixir and Rust are | such a perfect fit. Plus, some of the specifics will be | helpful for certain image-related things I 'm actively | working on, which is always nice. :) ) | Dowwie wrote: | If you're extending Elixir with Rust, familiarize yourself with | precompiled rustler: https://dashbit.co/blog/rustler-precompiled | benatkin wrote: | This makes me think of DotCloud, the precursor to Docker Inc. The | idea that you can run anything has been around for a while. I | don't see how Fly.io is especially good for Elixir. It seems to | be about delivering reliable resources for each service, and it | works no matter the web framework, as long as you have a PaaS | that's geared towards running arbitrary OCI images. These posts | seem a lot like the content on the DigitalOcean site, except | they're written by staffers instead of freelancers. | https://www.digitalocean.com/community/pages/write-for-digit... | mrdoops wrote: | Elixir does distribution and concurrency really well, so Fly | making multi-region deployments easy makes it a good fit. | benatkin wrote: | So is Fly good for small sites or is it good for huge sites? | What's a big customer? For small sites my idea of a multi- | region deployment is a single-region deployment that works in | multiple regions thanks to the magic of the Internet. | | I see this which mostly seems to be content sites. | https://www.wappalyzer.com/technologies/paas/fly-io/ Same on | the first forum result: https://community.fly.io/t/customer- | success-stories/4882 | peregrine wrote: | One of the interesting bits about Fly is we have our own | servers distributed globally and connected via wireguard. Which | makes it is trivial to setup Elixir/Erlang distribution | globally, and most importantly, close to your customers. While | its not a magic bullet it is pretty amazing to type a few | commands have a globally deployed and directly distributed | application. | | Further Fly builds its Dashboard internally with Phoenix | LiveView. We want the Phoenix and Ruby and Laravel and more | communities soon, to grow because we believe if they grow, we | will too. | benatkin wrote: | That's just internal networking isn't it? VPC on the big | clouds, DigitalOcean, and Vultr. Private Services on | render.com. | | I remember when Fly.io used to tout Firecracker but that is | just a KVM engine, along with QEMU used on a zillion hosts. | | What I'd like to see are customer success stories. | | Edit: looks like you have to set up your own cross-region | links on DigitalOcean and Vultr. So that interests me | somewhat. :) | brightball wrote: | This is essentially what has gotten me into Rust. Knowing how | easy Elixir makes it to offload a piece of my system that would | benefit from it without needing to write the entire thing in | Rust. | bglusman wrote: | I admit for a long time this was my primary motivation to learn | Rust, but, sadly, I haven't come across problems in years that | were CPU bound/where I needed something like Rust... Rustler | still looks like a great fit if needed, but, depending on the use | case, if I were CPU bound and needed to write my own code/not | just use a Rust library, I'd be as or more likely to look at | using Zig and Zigler[0], for much faster learning curve, and from | what I've read, easier tighter integration into elixir, including | I think language server integration. Some discussion here[1] | though I forget if I listened to this one or not. | | [0]https://github.com/ityonemo/zigler | [1]https://podcast.thinkingelixir.com/83 | packetlost wrote: | Efficient PLs are useful for latency sensitive applications | too, not just CPU bound ones. Though, that doesn't widen the | number of cases by much... | jimbob45 wrote: | _I haven 't come across problems in years that were CPU | bound/where I needed something like Rust_ | | This is where Rust falls short of C#: scaling to the issue at | hand. C# can build you a beautiful app at a high-level but also | lets you dick with pointers and assembly at a low level. Rust | insists on defaulting to pass-by-move and an arcane trait | system that hold it back from being usable in large projects. | FpUser wrote: | I remember MS reps coming to our offices in the 90s and | "Teaching" us how to program and how it is cool to have one | person writing GUI and the other "guru" writing high performance | C++ to be used in critical parts. | | I showed them a piece of software that was mighty fast, Internet | enabled and GUI intensive. They liked the software but asked | where did you get this particular screen control from. You've got | to see their faces when told that the whole software was written | by a single person in Delphi. | peregrine wrote: | Author here. The rustler team has really made a great developer | experience using Rust in Elixir and I just had to share. | mtremsal wrote: | This is amazing! The Gods have sent me the perfect excuse to | finally read all the rust ebooks I've been collecting! I have a | toy project where certain functions are CPU-bound and would make | for a perfect learning project. Very timely read! | maciejgryka wrote: | Shameless plug & also a point of support for the article: I used | that same stack to build https://regex.help/ (more details here | https://maciej.gryka.net/building-regex-help) | freedomben wrote: | Neat! You should definitely add a link to the github repo to | the main page of regex.help though, because I didn't realize it | was open source and I'll use it now. | | Github link for others: | https://github.com/maciejgryka/regex_help | satvikpendem wrote: | I used to use Elixir, but the lack of static types got to me | (especially since I prefer the type-driven development | methodology). Using Rust afterwards was great, plus it was faster | than the BEAM. I guess, why not use Rust entirely instead of as a | FFI into Elixir or other backend language? I've been using Axum | and it works pretty well. The only time I had to do FFI with Rust | was with Flutter via flutter_rust_bridge, for running a CRDT | library (automerge) that was implemented in Rust, for offline app | functionality. | shiryel wrote: | As it usually goes in programming, "it depends on your | objectives", there are things that are easier accomplished with | the ErlangVM than Rust. Also, if you want a language that uses | the ErlangVM and has static types, maybe you should take a look | at Glean[1]. | | In my case I prefer to work with Elixir because of the | community, as I find easier to work professionally with Elixir | than some other mainstream languages, as mostly projects | follows the same good practices, use the same tools and have | good documentation. | | [1] - https://gleam.run/ | kerkeslager wrote: | > I used to use Elixir, but the lack of static types got to me | (especially since I prefer the type-driven development | methodology). | | You might be interested in Gleam[1]. | | [1] https://gleam.run/ | satvikpendem wrote: | I used to use some Gleam back before the syntax change, when | it looked more like Haskell. I found that rather than using a | language with a comparatively smaller community, I'd rather | just use something that's well supported, so I settled on | Rust instead. | whalesalad wrote: | There is a great talk from the creator of the language on why | static types are not necessary. Of course there is nothing | wrong with wanting them and feeling that they are, but I think | he (Jose) makes really great arguments for why Elixir is the | way it is. https://www.youtube.com/watch?v=Jf5Hsa1KOc8 | hosh wrote: | Everyone have different needs. For us, OTP on top of pre- | emptive lightweight threads and a REPL in production is a huge | winner for troubleshooting, finding performance bottlenecks, | and reliability. | callamdelaney wrote: | Rust is faster, but that's like saying writing to memory is | faster than writing to a database - sure, it is - but the BEAM | is designed with something completely different in mind and is | still 'quick enough' for handling those cases. That said | dealing with elixir syntax is like rubbing sandpaper in your | eyes for 8 hours a day. | [deleted] | malkosta wrote: | > why not use Rust entirely instead of as a FFI into Elixir | | Because many times you value fault-tolerance and distribution | more than performance. | rapnie wrote: | There's a couple of Rust libs and frameworks inspired on | Erlang/OTP in 'best of both worlds' attempts, such as | https://lunatic.solutions | | I found others like Lunatic before, but cannot remember right | now. | malkosta wrote: | I guarantee your life will be simpler with Erlang. | aeturnum wrote: | I think the most attractive part of the Elixir / Erlang | ecosystem is BEAM and its ability to manage code, processes and | resources in an extremely parallel environment. Rust operates | at a lower level and it feels deceptive to just compare the | languages. | | That said - if you don't benefit from what BEAM has to offer - | I agree Rust is a really attractive alternative. | toast0 wrote: | Rust doesn't have a lot of good runtime introspection tools (or | they're very not obvious). If you're running a system with a | lot of concurrency, it's nice to be able to attach a debugger | and find out exactly what's going on with each of your tasks. | | I haven't seen hot loading for Rust (but a quick search shows | there's some out there), and I'm not sure how amenable Rust is | to dlopen and friends to force the issue. | | Erlang (and Elixir) have a constrained language that allows for | BEAM to be effectively premptive in a way that a Rust | concurrent runtime can't be. At every function call, BEAM | checks if the process should be preempted, and because the only | way to loop is recursion, a process _must_ call a function in a | finite amount of time. A Rust runtime cannot preempt, if you | need preemption, you 've got to use OS threads, which limits | capacity, or you need to accept cooperative task switching. | | Also, some of us are as anti-typing as you are pro-typing. :) | RhodesianHunter wrote: | >Also, some of us are as anti-typing as you are pro-typing. | | Assuming ample experience with both, how does one reach this | conclusion? | | I have yet to see a project of any size that needs to be | worked on by multiple teams and is written in an untyped | language not descend into dumpster fire. | ReflectedImage wrote: | Untyped languages work fine if you use them with | microservices. | | The only thing you can't do is have both untyped and | monolithic at the same time. | freedomben wrote: | I have yet to see a project of any size that needs to be | worked on by multiple teams not descend into dumpster fire. | Typing can definitely help, but it's just a small tool. | Java is a pretty typed language and I'm seen some real | doozy code bases in Java. | toast0 wrote: | I work on a lot of 'glue' issues, often with languages like | Perl, PHP, and Erlang (and a bit of Javascript here and | there). Specifying types all over the place in languages | like C, C++, Java, and Rust feels like it gets in the way | and limits more than it helps. (feelings more than data | here, of course) | | Sure, at boundaries between teams, you need to specify the | data in some way. That could be a type, but for me, often | the other team is using a different language than me, so it | needs to be a language agnostic type, and it can't include | unsigned numbers because Java can't cope, and it can't | include large integers because Javascript can't cope, etc. | Protobufs are popular, json is too. | | I have a lot of unpopular opinions though, and that's fine. | It's just tiresome that everyone wants to come in and add | types to things that don't need them. Also, I agree with | dllthomas, most developers and teams are capable of | creating dumpster fires in all sorts of environments, with | all sorts of tooling. :) | cglong wrote: | IMO, TypeScript strikes a great balance here. I loved the | way I could cast something to `any` when hacking | something out, then add proper type annotations once it's | ready to be productized. It also a did a good job with | type inference. | | Disclaimer: I work at Microsoft, but not in the Developer | Division | RhodesianHunter wrote: | You can absolutely create a dumpster fire in any | language. | | Putting the fire out in an untyped language is a | Herculean effort. | throwawaymaths wrote: | have you tried doing it in elixir? It's not that bad. | freedomben wrote: | Test coverage is, in my experience, much more important | factor than typing. A codebase with great testing is much | easier to aggressively refactor/change whether typed or | not. | | That said, a dumpster fire usually has no or little | tests, so maybe we're arguing non-existent hypotheticals | :| | di4na wrote: | In my experience it is even harder in a typed one because | now you have to deal with the type system nightmare they | built. So the compiler fight your refactoring. | bombela wrote: | Nobody code without a type system. The distinction is | build time vs runtime type checking. At build time you | catch bugs that would appear later at runtime. Which is | more costly to fix later. | toast0 wrote: | > Which is more costly to fix later. | | This assumption is changed, IMHO, by Erlang. Hot loading | makes the cost to make _small_ changes very low. So the | question becomes, do you pay the definite cost of build | time type checking (usually includes coding time type | annotation), or do you accept the _possible_ future cost | to making small fixes. | | Of course, if you work in an organization where even a | small fix requires months to release, then do all the | things you can to prevent making small mistakes. | sdeframond wrote: | The cost at runtime also includes loss of data, inferior | user experience, direct financial loss or even loss of | human life for some systems. | | It really depends on the domain but it definitely is more | than pushing an update. | ReflectedImage wrote: | Well no since unit tests run faster than build time. | [deleted] | packetlost wrote: | You never actually get away from types, they are a core | requirement of using any data beyond raw bytes. The | guarantees that a strong type system provide mean you can | be certain about certain things before your program even | runs. If that's a problem for you, you're likely just | leaving bugs on the table to be discovered at runtime. | [deleted] | toast0 wrote: | Conway's Law means you have to fix the organization | before you can fix the software. That's the real | Herculean effort. | fiddlerwoaroof wrote: | I tried Haskell for a while and switched to Common Lisp | (although I still follow Haskell from a distance). My | experience just doesn't match up with the claim that a | project of any size written in an untyped inevitably | descends into a dumpster fire. I've worked on largish | systems in several dynamically-typed languages and several | statically-typed and I personally haven't noticed any major | difference in overall productivity suggesting that static | types are better: they just have different friction points | and different ways of working work better in each paradigm. | RhodesianHunter wrote: | The issue isn't productivity. As far as just slamming out | code untyped languages are undeniably faster. | | The issue is working on projects once they've reached a | certain size where you have no idea what the intent of | the original author was and you maybe need to refactor, | add-in major pieces, or change anything with the | expectation that it continues to work. | fiddlerwoaroof wrote: | I'm including maintenance costs in "productivity". I've | worked on large dynamically typed codebases and never | experienced what you're talking about. | | I think it's a question of understanding how to work and | think without explicit types rather than something that | makes statically typed codebases easier to maintain. | ReflectedImage wrote: | Untyped code bases with microservices are the best code | bases out there by far. | | They are exceptionally easy to refactor, add-in new | parts, etc. | | The keyword is microservices, you need to know how to do | proper microservices if you are using untyped code. | throwawaymaths wrote: | >I have yet to see a project of any size that needs to be | worked on by multiple teams and is written in an untyped | language not descend into dumpster fire. | | Github? Dropbox? I mean they both eventually went to type | hints in their respective languages or migrated to a typed | language but for a long time I'm certain it wasn't. | RhodesianHunter wrote: | And I can pretty much guarantee you that some form of | dumpster, fire or other was the driving factor behind | those moves. | ollien wrote: | It's worth noting of course that ~Github~ Dropbox was the | driving force behind mypy | throwawaymaths wrote: | yes, that is exactly what I meant by "they both | eventually went to type hints", but doesn't github use | ruby? I think you mean sorbet? Dropbox was the driving | force behind mypy (IIRC). | ollien wrote: | bleh, I meant to say Dropbox. | dllthomas wrote: | While I'm pretty solidly in the "pro-typing" camp, it seems | worth acknowledging that such projects often turn into | dumpster fires in typed languages as well, even | expressively typed languages. | jjnoakes wrote: | Maybe, maybe not - but in my experience, a dumpster fire | with static types is easier to read and understand and | also easier to refactor. | dllthomas wrote: | That matches my experience as well. I just think we need | to be resistant to reading too much into "I've seen bad | code that X", because that can easily be true of almost | any X. | jibe wrote: | You think that statically typed languages don't often | turn into dumpster fires? Not my experience! Even though | there are real advantages. | throwawaymaths wrote: | it's certainly possible to write a nif that cooperates with | the VM so that its async yield points match up with the VM's | expectation of yield points. Definitely tricky to do | correctly in C (given that C doesn't have a yield statement, | lol, you have to structure it as an awkward tail call where | you pickle/unpickle whatever state you want to keep around or | unmarshal it from a passed struct). I'm not sure if that's so | easy to do in rust. | toast0 wrote: | Sure, you can do that for the code you write, but you can't | for the code you call. Any Erlang you write or call will | have this property, and most of the ERTS provided C code | will as well; either it's trivially finite, it is designed | to yield during the work, or it's neither but it hasn't | triggered anyone to fix it, with occasional deviations of | things that become known issues (like -- was for some time; | although it got fixed twice and is now fairly ok). | dxhdr wrote: | > Using Rust afterwards was great, plus it was faster than the | BEAM. I guess, why not use Rust entirely instead of as a FFI | into Elixir or other backend language? | | Sure, you just need to reimplement light-weight threading with | preemptive scheduling prioritizing latency over throughput, | extremely robust fault tolerance with a supervision hierarchy, | and runtime introspection with code hotloading capabilities. | Maybe you could add frictionless distributed system support as | well. | | No big deal, why not right? | lucasyvas wrote: | Is any of this needed though? For some use cases yes, but for | many no. It's possible the parent has no practical use for | these capabilities. | [deleted] | pdpi wrote: | If you're building a project that actually benefits from | Elixir/Erlang's features, you can have a constructive | discussion about whether those features justify sacrificing | static typing. If you don't actually benefit from those | features, "I tried to use a language that's unfit for my | purposes and found it unfit for my purposes" is a comment | of very limited value. | hexo wrote: | "Is Rust needed at all? For some use cases yes, but for | many no. It's possible the parent has no practical use for | its capabilities." | | You hear yourself? Yes? Good. | tines wrote: | You may not realize this, but your comment comes off as | being very snide and annoying, which I'm sure you didn't | intend. Try rewording things in a way that assumes good | faith, and besides making better relationships you'll | persuade people more effectively as well. | lucasyvas wrote: | The author gave static types and performance as examples | of things that matter to them that they clearly don't | feel Elixir does as well. It's probable they weren't the | target demographic for Elixir, like many aren't the | target demographic for Rust. | | The initial response made an assumption that all these | capabilities matter either way, and that's not true. | tessierashpool wrote: | This is not helpful. Please consider what if might be | like if you were to edit your comment to improve it. | dsiegel2275 wrote: | I used to use Elixir. I still do, but I used to too. | eikenberry wrote: | Could also be nice as it means the Rust parts are smaller and | so its slow compiler speed isn't as much of a bother. You get | the safety and runtime speed of Rust with the fast iteration | cycle of Elixir. Best of both worlds type of thing. | satvikpendem wrote: | I often find FFI more annoying than it should be (ie | something always breaks somewhere), I try to avoid it where | possible. | zinclozenge wrote: | I pretty much agree with this. As much as I liked the core | language, I absolutely hated using anything else in the | ecosystem, and in my opinion a lot of that was due to lack of | static types. Using Ecto as the main way of interacting with | the database was a miserable experience. Part of that was due | to skill issue I'm sure. | kerkeslager wrote: | > As much as I liked the core language, I absolutely hated | using anything else in the ecosystem, and in my opinion a lot | of that was due to lack of static types. | | You might be interested in Gleam[1]. | | [1] https://gleam.run/ | malkosta wrote: | > Ecto as the main way of interacting with the database was a | miserable experience | | That's very common when you don't know DBs. But DB savy | developers usually claim the opposite, because the syntax is | more familiar. | zinclozenge wrote: | > That's very common when you don't know DBs. | | I'm not a 20 year DBA greybeard veteran, but I'm | comfortable enough to write schemas and queries by hand | without any issue, and the entire time I wished I could do | just that instead of using Ecto. | sph wrote: | No one stops you from writing raw SQL with Ecto. | | But good luck creating composable SQL with raw string | interpolation, which Ecto excels at. | sergiotapia wrote: | On the flipside for me Ecto is the perfect balance between | ORM and writing raw SQL queries. I've used many different | ORMs like Entity Framework, ActiveRecord, Prisma, Ecto - Ecto | stands alone. | throwawaymaths wrote: | I believe... technically Ecto is not an ORM but a query | builder, which may be why you like it better than an ORM. | parthdesai wrote: | > Using Ecto as the main way of interacting with the database | was a miserable experience. | | Ecto is prolly one of the best ways to interact with db. | Genuinely curious, what other ORMs have you used? | zinclozenge wrote: | I usually just write the SQL, honestly. For the last 6ish | years of my career I've mainly been in the Golang world, so | the closest I've gotten to an ORM is a utility to scan rows | into structs. | freedomben wrote: | Interesting, I usually just write the SQL too in most | projects, but in Elixir I _love_ Ecto because it 's so | close to the SQL but has an elegant and powerful way to | handle interpolated values. | vlunkr wrote: | I'm in the same boat with Elixir. I love many aspects of the | language, but it borrows the fast-and-loose type ecosystem of | ruby. | | nil is an especially big problem. Any value could be nil, and | this will absolutely bite you over and over. nil even allows | you to use square brackets for some reason | (some_nil_value[:some_key]) which is a great way to disguise | the actual issue. | | There is optional type checking with Dialyzer, which is good | but has some problems. The warning output can be really hard to | read, and unless you're diligent in using it across most of | your project, it's not very useful, because you'll end up with | 'any' values all over. | OkayPhysicist wrote: | I disagree. Any value could be nil, but any value could be 5, | too. In fact, nil is just like any other atom. Elixir shines | when you lean on pattern matching as much as possible. Your | functions should unpack as much as possible within the | function definition, frankly the "if" macro is completely | superfluous to case and in rare cases cond. You'll find that | you match the data you want, and thus reject anything else. | | Square bracket dictionary accesses are a code smell, because | you should be using %{^key = val} = dict or Map.fetch(map, | key) or rarely Map.fetch!(map, key). | | If you do that, managing typing in Elixir just boils down to | defining structs to differentiate cases where dictionary A | and dictionary B contain similar keys but strictly are not | interchangeable. | throwawaymaths wrote: | Elixir is incredibly consistent with how it uses nil. It does | take a bit of work -- you have to really pay attention to the | convention of fetch! vs fetch vs get -- and often times | library maintainers are not... always the best at that... but | for all the problems that dynamic languages has, nil in | elixir is pretty low on the list. I think I get bitten by | maybe one a year, and it causes the sporadic report on | sentry, and then I go and fix it, and that's that. | | That access acts on nil is unfortunate, but it's necessary | for things like get_in. | pawelduda wrote: | I used this in past, but there were a lot of people saying that | NIFs/ports are dangerous to use. Did any of this change or are | there tried and tested practices that can be applied? What I used | this for wasn't critical app so I didn't mind it going down. | | IIRC one threat was Rust sharing memory with BEAM which could | exhaust it and cause OOM crash? | peregrine wrote: | Nif's are _always_ a risk to deploy cause they run embedded in | the Beam runtime. That said we all use many nif 's to do all | kinds of stuff and its fine. | | I go into this in the article a little but but the ruslter team | has made dirtycpu and dirtyio macro's to help reduce the risks. | toast0 wrote: | I wouldn't use the word dangerous. NIFs and (linked in) ports | are a risk, yes. You're loading native code, and you don't have | intrinsic protection against it doing naughty things that alter | the underlying shared state in unapproved ways. Things like | writing to improper addresses, closing improper filehandles, | opening filehandles and leaking them, leaking memory, other | improper use of syscalls, or just running for too long. | | The only proper solution is to audit and understand the code | you're running, but hoping it's fine often works too; maybe | formal methods, but to a first approximation, nobody uses | those. Did you audit all of ERTS and/or OTP? I'm guessing | probably not, but it's there to review if you run into a | problem. | | IMHO, it's not worrying about if BEAM will crash; worry about | it not crashing instead. If your Rust NIF ties up a scheduler | with an infinite loop, that has the potentially to lock up the | whole BEAM once another scheduler needs to do something that | requires full cross scheduler coordination. | | BEAM can certainly crash on OOM; although I recommend setting a | ulimit to ensure it will, because when it crashes, you can | recover. I've also run into situations where instead of | crashing or being killed by the OS OOM killer (which is close | enough to crashing), the OS gets into some tricky to debug | state where your application is neither functioning nor killed. | Sometimes, you even get into a state where BEAM is making | progress, but very slowly; that's a fate worse than death. | | If you follow the Erlang philosophy, you'll have a recovery | strategy from crashes or other deaths. Heart can be used to | turn completely blocked into death, although I never used it | professionally. But you've still got to worry about working but | not well. | OkayPhysicist wrote: | NIFs are dangerous, ports are not. Basically a NIF runs in the | same memory space as the BEAM, so misbehavior of the NIF can | crash the entire application. On the other hand, they have | wildly better performance than ports, which have to operate | through STDI/O. | | The Rust / BEAM memory sharing problem does exist, but it's not | nearly as bad as in more traditional C NIFs, because almost all | C programs leak memory due to bad manual memory management. | Hence all the buzz about Elixir+Rust. | throwawaymaths wrote: | ports can be dangerous! One time my server lost performance | because of a lot of zombie processes. | toast0 wrote: | I personally include port drivers in with ports, which gives | you the same level of shared runtime environment as NIFs, | with the benefits and drawbacks. Sometimes it makes more | sense to interface as a port rather than as a function. Of | course, sometimes it makes more sense to interface as a | C-node rather than either; then you can be on a totally | isolated machine, and the C-node can even crash or otherwise | disable the whole OS and your Erlang node will be fine. | OkayPhysicist wrote: | What's the benefit of a port driver over a NIF? | waynesonfire wrote: | IO in erlang is slow, is Rustler a good candidate to improve IO | intensive applications? | throwawaymaths wrote: | Where did you get this idea? Depending on your task, Erlang can | be very fast with IO because it will aggressively use | writev/readv instead of write. Obviously, you can do this if | you "know about it" in low level langs, but it might be a pain. | | Erlang is generally considered to be compute-slow (which is | generally the case without dropping to nifs). | weatherlight wrote: | I/O in beam languages is considered pretty fast, are you sure | you aren't mistaken? | toast0 wrote: | Is IO in Erlang slow? I never got that impression; iolists are | a good fit for scatter/gather I/O, which reduces copying, and | Erlang supports kqueue, epoll, and I believe similar on | Windows. I don't follow Erlang on Linux closely, so I don't | know if there's any movement towards io_uring, which does seem | promising to help with throughput. | | Either way, I wouldn't expect doing I/O in NIFs or ports to | substantially improve throughput, unless you're also moving | significant processing into that layer as well, or you're going | to end up doing substantially the same level of marshaling work | as ERTS does, just in a different language. Setting up a | different set of kqueue/epoll descriptors sounds like a lot of | work for not much gain too, IMHO; again, maybe io_uring would | be useful, but I think you'd be better served to bite the | bullet and integrate it with ERTS. | sph wrote: | IO in Erlang is faster than many other managed languages, | thanks to stuff like IO Lists that are dealt with very | efficiently through iovec syscalls (readv, writev). | | Then add efficient pattern matching for binary data, and | networked servers on the BEAM are the most ergonomic than any | other language. | | All this stuff that the BEAM offers you out of the box can be | replicated in any native language with a lot of boilerplate and | ceremony. | | Your "Hello, <name>" webapp in Rust will probably need two | allocations and a string concatenation, while on the BEAM, if | constructed as an iolist, it's a single writev syscall, using a | static "Hello, " string and a shared "<name>" reference from | the parsed HTTP data. ___________________________________________________________________ (page generated 2023-04-13 23:00 UTC)