TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Playground Wisdom: Threads Beat Async/Await

171 点作者 samwillis6 个月前

19 条评论

Const-me6 个月前
The article seems specific to JavaScript, C# is different.<p>&gt; you cannot await in a sync function<p>In C# it’s easy to block the current thread waiting for an async task to complete, see Task.Wait method.<p>&gt; since it will never resolve, you can also never await it<p>In C#, awaiting for things which never complete is not that bad, the standard library has Task.WhenAny() method for that.<p>&gt; let&#x27;s talk about C#. Here the origin story is once again entirely different<p>Originally, NT kernel was designed for SMP from the ground up, supports asynchronous operations on handles like files and sockets, and since NT 3.5 the kernel includes support for thread pool to dispatch IO completions: <a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Input&#x2F;output_completion_port" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Input&#x2F;output_completion_port</a><p>Overlapped I&#x2F;O and especially IOCP are hard to use directly. When Microsoft designed initial version of .NET, they implemented thread pool and IOCP inside the runtime, and exposed higher-level APIs to use them. Stuff like Stream.BeginRead &#x2F; Stream.EndRead available since .NET 1.1 in 2003, the design pattern is called Asynchronous Programming Model (APM).<p>Async&#x2F;await language feature introduced in .NET 4.5 in 2012 is a thin layer of sugar on top of these begin&#x2F;end asynchronous APIs which were always there. BTW, if you have a pair of begin&#x2F;end methods, converting into async&#x2F;await takes 1 line of code, see TaskFactory.FromAsync.
评论 #42219210 未加载
评论 #42181507 未加载
评论 #42179219 未加载
评论 #42184388 未加载
arctek6 个月前
I actually think out of any language async&#x2F;await makes the most sense for javascript.<p>In the first example: there is no such thing as a blocking sleep in javascript. What people use as sleep is just a promise wrapper around a setTimeout call. setTimeout has always created microtasks, so calling a sleep inline would do nothing to halt execution.<p>I do agree that dangling Promises are annoying and Promise.race is especially bad as it doesn&#x27;t do what you expect: finish the fastest promise and cancel the other. It will actually eventually resolve both but you will only get one result.<p>Realistically in JS you write your long running async functions to take an AbortController wrapper that also provides a sleep function, then in your outer loop you check the signal isn&#x27;t aborted and the wrapper class also handles calling clearTimeout on wrapped sleep functions to stop sleeping&#x2F;pending setTimeouts and exit your loop&#x2F;function.
评论 #42221384 未加载
评论 #42227394 未加载
评论 #42227312 未加载
serbuvlad6 个月前
As someone who has only written serious applications in single-threaded, or manually threaded C&#x2F;C++, and concurrent applications in go using goroutines, channels, and all that fun stuff, I always find the discussion around async&#x2F;await fascinating. Especially since it seems to be so ubiquitous in modern programming, outside of my sphere.<p>But one thing is: I don&#x27;t get it. Why can&#x27;t I await in a normal function? await sounds blocking. If async functions return promises, why can&#x27;t I launch multiple async functions, then await on each of them, in a non-async function that does not return a promise?<p>I get there are answers to my questions. I get await means &quot;yeald if not ready&quot; and if the function is not async &quot;yeald&quot; is meaningless. But I find it a very strange way of thinking nonetheless.
评论 #42218662 未加载
评论 #42180466 未加载
评论 #42218668 未加载
评论 #42224994 未加载
评论 #42218703 未加载
评论 #42219088 未加载
评论 #42220766 未加载
评论 #42218667 未加载
评论 #42219003 未加载
评论 #42186359 未加载
评论 #42178953 未加载
评论 #42219362 未加载
评论 #42219222 未加载
cryptonector6 个月前
Threads are definitely not _the_ answer but _an_ answer.<p>You can have as many threads as hardware threads, but in each thread you want continuation passing style (CPS) or async-await (which is a lot like syntactic sugar for CPS). Why? Because threads let you smear program state over a large stack, increasing memory footprint, while CPS &#x2F; async-await forces you to make all the state explicit and compressed, thus optimizing memory footprint. This is not a small thing. If you have thread-per-client services, each thread will need a sizeable stack, each stack with a guard page -- even with virtual memory that&#x27;s expensive, both to set up and in terms of total memory footprint.<p>Between memory per client, L1&#x2F;L2 cache footprint per client, page faults (to grow the stack), and context switching overhead, thread-per-client is much more expensive than NPROC threads doing CPS or async-await. If you compress the program state per client you can fit more clients in the same amount of memory, and the overhead of switching from one client to another is lower, thus you can have more clients.<p>This is the reason that async I&#x2F;O is the key to solving the &quot;C10K&quot; problem: it forces the programmer to compress per-client program state.<p>But if you don&#x27;t need to cater to C10K (or C10M) then thread-per-client is definitely simpler.<p>So IMO it&#x27;s really about trade-offs. Does your service need to be C10K? How much are you paying for the hardware&#x2F;cloud you&#x27;re running it on? And so on. Being more efficient will be more costly in developer cycles -- that can be <i>very</i> expensive, and that&#x27;s the reason that research into async-await is ongoing: hopefully it can make C10K dev cheaper.<p>But remember, rewrites cost even more than doing it right the first time.
评论 #42220100 未加载
whoisthemachine6 个月前
&gt; Your Child Loves Actor Frameworks<p>It turns out, Promises <i>are</i> actors. Very simple actors that can have one and only one message that upon resolution they dispatch to all other subscribed actors [0]. So children might love Promises and async&#x2F;await then?<p>Personally, I&#x27;ve often thought the resolution to the &quot;color&quot; debate would be for a new language to make all public interfaces between modules &quot;Promises&quot; by default. Then the default assumption is &quot;if I call this public function it could take some time to complete&quot;. Everything acting synchronously should be an implementation detail that is nice if it works out.<p><a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Futures_and_promises#Semantics_of_futures_in_the_actor_model" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Futures_and_promises#Semantics...</a>
评论 #42219081 未加载
评论 #42221864 未加载
mst6 个月前
&gt; Stackless did not have a bright future because the stackless nature meant that you could not have interleaving Python -&gt; C -&gt; Python calls and suspend with them on the stack.<p>perl&#x27;s Coro.pm (<a href="https:&#x2F;&#x2F;p3rl.org&#x2F;Coro" rel="nofollow">https:&#x2F;&#x2F;p3rl.org&#x2F;Coro</a>) includes a C-level coroutine implementation so if you call back into perl code from C code, it marks that underlying coroutine as occupied until it returns back through the C code into something that&#x27;s perl all the way down.<p>(I got rapidly annoyed with it because I kept managing to segfault the damn thing, but I am the sort of programmer who seems to manage to break everything, and a bunch of other people whose abilities I respect have built substantial systems using it without suffering from the same; please either assume for the sake of argument that I was holding it wrong, or at least consider that the concept is extremely neat even if a tad on the tricky side to make fully robust)
RantyDave6 个月前
Almost as an aside the article makes an interesting point: memory accesses can block. Presumably if it blocks because it&#x27;s accessing a piece of hardware the operating system schedules another thread on that core ... but what if it blocks on a &#x27;normal&#x27; memory access? Does it stall the core entirely? Can &#x27;hyperthreading&#x27; briefly run another thread? Does out of order execution make it suddenly not a problem? Surely it doesn&#x27;t go all the way down to the OS?
评论 #42219050 未加载
评论 #42181450 未加载
评论 #42218773 未加载
NeutralForest6 个月前
I thought that was interesting and I definitely get the frustration in some aspect. I&#x27;m mostly familiar with Python and the function &quot;coloring&quot; issue is so annoying as it forces you to have two APIs depending on async or not (look at SQLAlchemy for example). The ergonomics are bad in general and I don&#x27;t really like having to deal with, for example, awaiting for a result that will be needed in a sync function.<p>That being said, some alternatives were mentioned (structured concurrency à la Go) but I&#x27;d like to hear about people in BEAM land (Elixir) and what they think about it. Though I understand that for system languages, handling concurrency through a VM is not an option.
评论 #42172131 未加载
评论 #42218719 未加载
评论 #42179417 未加载
exabrial6 个月前
&gt; The language that I think actually go this right is modern Java. Project Loom in Java has coroutines and all the bells and whistles under the hood, but what it exposes to the developer is good old threads. There are virtual threads, which are mounted on carrier OS threads, and these virtual threads can travel from thread to thread. If you end up issuing a blocking call on a virtual thread, it yields to the scheduler.<p>I completely agree! They studied a lot of &quot;bad&quot; implementations and moved slow to get it right
manmal6 个月前
I view Swift‘s Tasks as a thread-like abstraction that does what the author is asking for. Not every Task is providing structured concurrency in the strict sense, because cancellation has to be managed explicitly for the default Task constructor. But Tasks have a defined runtime, cancellation, and error propagation, if one chooses to use a TaskGroup, async let, or adds some glue code. The tools to achieve this are all there.
FlyingSnake6 个月前
I expected to see Swift but seems like most such discussions overlook it. Here’s a great discussion that goes deeper into it: <a href="https:&#x2F;&#x2F;forums.swift.org&#x2F;t&#x2F;concurrency-structured-concurrency&#x2F;41622" rel="nofollow">https:&#x2F;&#x2F;forums.swift.org&#x2F;t&#x2F;concurrency-structured-concurrenc...</a>
nextcaller6 个月前
I&#x27;m still not sure if function coloring is also a problem in javascript. The problem became very clear in other languages like python or c#. But in javascript i&#x27;ve been writing code only awaiting a function when I need to and haven&#x27;t ran into issues. I might write some simple experiment to check myself.
评论 #42222110 未加载
pwdisswordfishz6 个月前
&gt; Go, for instance, gets away without most of this, and that does not make it an inferior language!<p>Yes, it does. Among other things.
huem0n6 个月前
&gt; The closest equivalent would be a stupid function that calls a very long running sleep<p>I disagree. The equivalent would be a thread that&#x27;s never joined, like a thread with an infinite loop
mark_l_watson6 个月前
Nice read, and the article got me to take a look at Java’s project Loom and then Eric Normand’s writeup on Loom and threading options for Clojure.<p>Good stuff.
agentkilo6 个月前
People should try Janet (the programming language). Its fiber abstraction got everything right IMO.<p>Functions in Janet don&#x27;t have &quot;colors&quot;, since fiber scheduling is built-in to the runtime in a lower level. You can call &quot;async&quot; functions from anywhere, and Janet&#x27;s event loop would handle it for you. It&#x27;s so ergonomic that it almost feels like Erlang.<p>Janet has something akin to Erlang&#x27;s supervisor pattern too, which, IMO, is a decent implementation of &quot;structured concurrency&quot; mentioned in the article.
andrewstuart6 个月前
Feels academic because despite the concerns raised, I only experience async&#x2F;await as a good thing in real world.
评论 #42193696 未加载
vanderZwan6 个月前
I&#x27;m a little annoyed with the repeated claim in the article that &quot;threads&quot; do not exist in JavaScript when the MDN page on web workers[0] starts with:<p>&gt; <i>Web Workers makes it possible to run a script operation in a background thread separate from the main execution thread of a web application.</i><p>Sure, it&#x27;s not like a unix thread, it&#x27;s message-passing based instead. Because event-based concurrency came first, and so the natural way to add threads to it was to make them message-passing based. Given that the author expresses their love of the actor model makes it extra surprising they don&#x27;t mention it, since it seems to be pretty much what they want semantically speaking.<p>If you want to avoid promises you can also have lots of fun with workers and message channels[1] to implement your own concurrency approaches.<p>What I&#x27;m even more annoyed by is that everyone always acts like Nathaniel J. Smith invented structured concurrency. There&#x27;s an entire field of overlooked concurrency paradigms in the family of dataflow programming languages[2], which goes back all the way to the eighties. My personal recent-ish favorite among them being Céu[3][4]. Funny enough it&#x27;s also yet another language with a completely different take on what &quot;async&quot; and &quot;await&quot; mean.<p>Céu an imperative language centered where the concurrency used both asynchronous events <i>and sychronous ones</i>. The former represents external events. The latter internal ones.<p>Code flow can be split into synchronous concurrent paths by writing out each path directly, similar to if .. else .. branches. Instead of &quot;branches&quot; they&#x27;re called &quot;trails&quot;, and started with par&#x2F;or and par&#x2F;and as keywords.<p><pre><code> par&#x2F;or do loop do await 1s; _printf(&quot;Hello &quot;); await 1s; _printf(&quot;World!\n&quot;); end with await async do emit 10s; end end </code></pre> Trails are visited in lexical order. If an &quot;await&quot; keyword is encountered the trail is suspended until the event it waits for fires. This is the benefit of synchronous, single-threaded concurrency: have the benefit of allowing the order in which events fire deterministic and expressible in lexical order.<p>As mentioned, synchronous events represent external inputs. From the perspective of a single module of single-threaded code. they&#x27;re queued up and get resolved one at a time after the current series of synchronous events finishes and all activated trails in the module are suspended (i.e. awaiting another external event to wake one or more of them in lexical order).<p>The &quot;async&quot; keyword exists solely to simulate such an asynchronous external event inside the code. In the above example, the &quot;emit 10s&quot; simulates passing 10 seconds of time (and could also have been written as a simple &quot;await 5s&quot;, but then it wouldn&#x27;t have demonstrated the async keyword).<p>So in the above example, the first trail is entered, starting a loop. Then at each &quot;await 1s&quot; it suspends until one second has passed, after which it resumes from where it awaited. The second trail is entered after the first trails suspends the first time, then suspends for ten seconds. After that the second trail finishes. Because we split into concurrent trails using &quot;par&#x2F;or&quot;, all trails are aborted whenever any trail finishes. This means that we should have printed &quot;Hello World!&quot; five times. However, if the two trails had been written in reverse order:<p><pre><code> par&#x2F;or do await async do emit 10s; end with loop do await 1s; _printf(&quot;Hello &quot;); await 1s; _printf(&quot;World!\n&quot;); end end </code></pre> ... the first trail would have finished first, aborting the last &quot;await 1s&quot; of the second trail, resulting in one half finished &quot;Hello &quot; without a newline.<p>The neat thing is that all of the synchronous concurrency can be compiled down to a very minimal finite state machine with microscopic memory overhead, making it usable in embedded contexts.<p>(Tangent: the above is the old syntax btw, it is currently being rewritten into a version called Dynamic Céu with more features, and a different syntax whose terminology is also more in line with what the mainstream consensus is for various concurrency terms[5][6]).<p>[0] <a href="https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Web_Workers_API&#x2F;Using_web_workers" rel="nofollow">https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Web_Workers...</a><p>[1] <a href="https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;MessageChannel" rel="nofollow">https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;MessageChan...</a><p>[2] <a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dataflow_programming" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dataflow_programming</a><p>[3] <a href="https:&#x2F;&#x2F;github.com&#x2F;ceu-lang&#x2F;ceu">https:&#x2F;&#x2F;github.com&#x2F;ceu-lang&#x2F;ceu</a><p>[4] <a href="https:&#x2F;&#x2F;ceu-lang.github.io&#x2F;ceu&#x2F;out&#x2F;manual&#x2F;v0.30&#x2F;" rel="nofollow">https:&#x2F;&#x2F;ceu-lang.github.io&#x2F;ceu&#x2F;out&#x2F;manual&#x2F;v0.30&#x2F;</a><p>[5] <a href="https:&#x2F;&#x2F;github.com&#x2F;fsantanna&#x2F;dceu?tab=readme-ov-file#the-programming-language-ceu-v05">https:&#x2F;&#x2F;github.com&#x2F;fsantanna&#x2F;dceu?tab=readme-ov-file#the-pro...</a><p>[6] <a href="https:&#x2F;&#x2F;github.com&#x2F;fsantanna&#x2F;dceu&#x2F;blob&#x2F;main&#x2F;doc&#x2F;manual-out.md">https:&#x2F;&#x2F;github.com&#x2F;fsantanna&#x2F;dceu&#x2F;blob&#x2F;main&#x2F;doc&#x2F;manual-out.m...</a>
unscaled6 个月前
I think most of the arguments in this essay rely on this single premise: &quot;The second thing I want you to take away is that imperative languages are not inferior to functional ones.&quot;<p>There is an implied assumption that async&#x2F;await is a &quot;functional feature&quot; that was pushed into a bunch of innocent imperative languages and polluted them. But there is one giant problem with this assumption: async&#x2F;await is not a functional feature. If anything, it&#x27;s the epitome of an imperative flow-control feature.<p>There are many kinds of functional languages out there, but I think the best common denominator for a primarily functional language nowadays is exactly this: in functional languages control flow structures are first class citizens, and they can be customized by the programmer. In fact, most control flow structures are basically just functions, and the one that aren&#x27;t (e.g. pattern matching in ML-like languages and monadic comprehensions in Haskell-inspired languages) are extremely generic, and their behavior depends on the types you feed into them. There are other emphasis points that you see in particular families of languages such as pattern matching, strict data immutability or lazy computation — but none of these is a core functional concept.<p>The interesting point I want to point out is that no primarily functional language that I know actually has async&#x2F;await. Some of them have monads and these monads could be used for something like async&#x2F;await but that&#x27;s not a very common use, and monad comprehensions can be used for other things. For instance, you could use do expressions in Haskell (or for expressions in Scala) to operate on multiple lists at once. The same behavior is possible with nested for-loops in virtually every modern imperative language, but nobody has blamed Algol for &quot;polluting&quot; the purity of our Fortran gotos and arithmetic ifs with this &quot;fancy functional garbage monad from damned ivory tower Academia&quot;. That would be absurd, not only because no programming language with monadic comprehensions existed back then, but also because for loops are a very syntax for a very specific thing that can be done with monadic expression. They turn a very abstract functional concept into a highly specific — and highly <i>imperative</i> — feature. The same is true for await. It&#x27;s an imperative construct that instructs the runtime to suspend (or the compiler to turn the current function into a state machine).<p>So no, async&#x2F;await does not have anything to do with functional-language envy and is, in fact, a feature that is quite antithetical to functional programming. If there is any theoretical paradigm behind async&#x2F;await (vs. just using green threads), it&#x27;s strong typing and especially the idea of representing effects by types. This is somewhat close to fully-fledged Effect Systems (in languages such as a Koka), but not as powerful. The general idea is that certain functions behave in a way that is &quot;infective&quot; — in other words, if foo() calls bar() which in-turn calls doStuff(), it might be impacted by some side-effect of doStuff(). In order to prevent unpleasant surprises, we want to mark this thing that doStuff does in the function signature (either using an extra argument, a return type wrapper or just an extra modifier like &quot;async&quot;).<p>In a pure language like Haskell, everything from I&#x2F;O to mutable memory requires specifying an effect and this is usually done through monadic return types. But even the very first version of Java (Ron Pressler&#x27;s ideal untarnished &quot;imperative&quot; language) has effects (or &quot;colors&quot;) which still remain in the language: checked exceptions. They are just as infective as async I&#x2F;O. If you don&#x27;t handle exceptions in place, a function marked with &quot;throws IOException&quot; (basically almost any function that deals with I&#x2F;O) can only be called by another function marked with &quot;throws IOException&quot;. What&#x27;s worse, unlike JavaScript which only has two colors (async and non-async), Java has an infinite number colors!<p>The description above sounds horrible, but it&#x27;s not. Checked exceptions are widely believed to be a mistake[1], but they don&#x27;t bother Java developers enough to make the language unusable. You can always just wrap them with another exception and rethrow. The ergonomics could have been made slightly better, but they&#x27;re decent enough. But the same can be said for async&#x2F;await. If you take a language with a similar feature that is close to Java (C# or Kotlin), you&#x27;ll see the asynchronous functions can still run as blocking code from inside synchronous functions, while synchronous functions can be scheduled on another thread from a synchronous function. The ergonomics for doing that are not any harder than wrapping exceptions.<p>In addition to that, the advantages of marking a function that runs asynchronous I&#x2F;O (just like marking a function that throws an exception) are obvious, even if the move itself is controversial. These functions generally involve potentially slow network I&#x2F;O and you don&#x27;t want to call them by mistake. If you think that never happens, here is the standard Java API for constructing an InetAddress object from a string representing an IPv4 or IPv6 address: InetAddress.getByName()[2]. Unfortunately, if your IP address is invalid, this function may block while trying to resolve it as a domain name. That&#x27;s plain bad API design, but APIs that can block in surprising ways are abundant, so you cannot argue that async&#x2F;await doesn&#x27;t introduce additional safety.<p>But let&#x27;s face it — in most cases choosing async&#x2F;await vs. green threads for an imperative language is a matter of getting the right trade-off. Async&#x2F;Await schedulers are easier to implement (they don&#x27;t need to deal with segmented&#x2F;relocatable&#x2F;growable stacks) and do not require runtime support. Async&#x2F;await also exhibits more efficient memory usage, and arguably better performance in scenarios that do not involve a long call-graph of async functions. Async&#x2F;await schedulers also integrates more nicely with blocking native code that is used as a library (i.e. C&#x2F;C++, Objective C or Rust code). With green threads, you just cannot run this code directly from the virtual thread and if the code is blocking, your life becomes even harder (especially if you don&#x27;t have access to kernel threads). Even with full control of the runtime, you&#x27;d usually end up with a certain amount of overhead for native calls[3].<p>Considering these trade-offs, async&#x2F;await is perfect in scenarios like below:<p>1. JavaScript had multiple implementations. Not only were most of them single-threaded, they would also need a major overhaul to support virtual threads even if a thread API was specified.<p>2. Rust actually tried green threads and abandoned them. The performance was abysmal for a language that seeks zero-cost abstraction and the system programming requirements for Rust made them a deal breaker even if this wasn&#x27;t the case. Rust just had to support pluggable runtimes and mandating dynamic stacks just won&#x27;t work inside the Kernel or in soft real-time systems.<p>3. Swift had to interoperate with a large amount of Objective C called that was already using callbacks for asynchronous I&#x2F;O (this is what they had). In addition, it is not garbage-collected language, and it still needed to call a lot of C and Objective C APIs, even if that was wrapped by nice Swift classes.<p>4. C# already had a Promise-like Task mechanism that evolved around wrapping native windows asynchronous I&#x2F;O. If .Net was redesigned from scratch nowadays, they could have very well went with green threads, but the way .Net developed, this would have just introduced a lot of compatibility issues for almost no gains.<p>5. Python had the GIL, as the article already mentioned. But even with patching runtime I&#x2F;O functions (like greenlet — or more accurately, gevent[4] — did), there were many third party libraries relying on native code. Python just went with the more compatible approach.<p>6. Java did not have any established standard for asynchronous I&#x2F;O. CompletableFuture was introuced in Java 8, but it wasn&#x27;t as widely adopted (especially in the standard library) as the C# Task was. Java also had gauranteed full control of the runtime (unlike JavaScript and Rust), it was garbage collected (unlike Rust and Swift) and it had less reliance on native code than Swift, Pre-.NET Core C# or Python. On the other hand, Java had a lot of crucial blocking APIs that haven&#x27;t been updated to use CompletableFuture, like JDBC and Servlet (Async Servlets were cumbersome and never caught on). Introducing async&#x2F;await to Java would mean having to rewrite or significantly refactor all existing frameworks in order to support them. That was not a very palatable choice, so again, Java did the correct thing and went with virtual threads.<p>If you look at all of these use cases, you&#x27;d see all of these languages seem to have made the right pragmatic choice. Unless you are designing a new language from scratch (and that language is garbage collected and doesn&#x27;t need to be compatible with another language or deal with a lot of existing native code), you can go with the ideological argument of &quot;I want my function to be colorless&quot; (or, inversely, you can go with the ideological argument of &quot;I want all suspending functions to be marked explicitly&quot;). In all other cases, pragmatism should win.<p>---<p>[1] Although it mostly comes to bad composability — checked result types work very well in Rust.<p>[2] <a href="https:&#x2F;&#x2F;docs.oracle.com&#x2F;en&#x2F;java&#x2F;javase&#x2F;17&#x2F;docs&#x2F;api&#x2F;java.base&#x2F;java&#x2F;net&#x2F;InetAddress.html#getByName(java.lang.String)" rel="nofollow">https:&#x2F;&#x2F;docs.oracle.com&#x2F;en&#x2F;java&#x2F;javase&#x2F;17&#x2F;docs&#x2F;api&#x2F;java.base...</a><p>[3] See the article blelow for the overhead in Go. Keep in mind that the Go team has put a lot of effort into optimizing Cgo calls and reducing this overhead, but they still cannot eliminate it entirely. <a href="https:&#x2F;&#x2F;shane.ai&#x2F;posts&#x2F;cgo-performance-in-go1.21&#x2F;" rel="nofollow">https:&#x2F;&#x2F;shane.ai&#x2F;posts&#x2F;cgo-performance-in-go1.21&#x2F;</a><p>[4] <a href="https:&#x2F;&#x2F;www.gevent.org&#x2F;" rel="nofollow">https:&#x2F;&#x2F;www.gevent.org&#x2F;</a>
评论 #42220646 未加载
评论 #42203891 未加载
评论 #42181574 未加载
评论 #42222074 未加载