Hacker Newsnew | past | comments | ask | show | jobs | submit | tcfhgj's commentslogin

if I fork a repository to my forge, I expect my forge to have an independent copy of the repo

How does that fix "when one node goes offline you may not have any upstream to pull from"? You'd still have your own local copy—just like git—but you wouldn't be able to access any sense of "upstream"

By hosting a knot.

You may ask, well, that's like hosting forgejo or any other git server, where is the federation?

Tangled uses a protocol. So knots would adhere to that protocol allowing to pull from any upstream.

That's my understanding of federation. not saying tangled will go as far as figuring out discovery across their cloud hosted knots and self hosted infra. But that can be done, and claiming to be able to pulling from any repo with a single identy would imply just that.


> If people want to find software, they search GitHub.

people really do that?


The only time I ever search GitHub is when I'm trying to debug or understand some esoteric API (usually Apple-specific) and I'm looking for anybody else who has actually used the god damned thing.

If I'm looking for software/libs/etc, GitHub search is the absolute last thing I would even think to look for.


Mentioning facts is not constructive, interesting.

How constructive are ad hominem arguments?


This really makes me angry and more sympathetic towards the tyre extinguishers


> This functionality is experimental, and comes with a number of requirements and limitations.

I assume that answers your question.


So once it's out of the experimental stage it won't be an intrusive hack anymore?

Could you point out the issue here?

Why does async make it harder to reason about when resources are released?


Basically it’s the non-linear execution flow creating situations which are harder to reason about. Here’s an example I’m trying to help a Node team fix right now: something is blocking the main loop long enough that some of the API calls made in various places are timing out or getting auth errors due to the signature expiring between when the request was prepared and when it is actually dispatched because that’s sporadically tend of seconds instead of milliseconds. Because it’s all async calls, there are hundreds of places which have to be checked whereas if it was threaded this class of error either wouldn’t be possible or would be limited to the same thread or an explicit synchronization primitive for something like a concurrency limit on the number of simultaneous HTTP requests to a given target. Also, the call stack and other context is unhelpful until you put effort into observability for everything because you need to know what happened between hitting await and the exception deep in code which doesn’t share a call stack.

I still don't get it.

The execution flows of individual async tasks are still linear, much like individual threads are linear.

Scheduling (tasks by the async runtime vs threads by the OS), however results in random execution order either way.

If there is a slow resource, both, async tasks as well as threads will pile potentially increasing response times.

Wether async or threads, you can easily put a concurrency limit on resources using e.g. semaphores [1]:

- limit yourself to x connections (either wait or return an error)

- limit the resource to x concurrent usages (either wait until other users leave, or return an error)

Regarding blocking the main loop: with async and non-blocking operations, how would something block the main loop? And why would the main loop being blocked cause API calls being timing out? Is it single threaded?

[1]: https://docs.rs/tokio/latest/tokio/sync/struct.Semaphore.htm...


> The execution flows of individual async tasks are still linear, much like individual threads are linear.

Think about what happens:

1. Request one hits an await in foo()

2. Runtime switches to request two in bar() until it awaits

3. Runtime switches to request three in baaz(), which blocks the loop for a while

4. Request one gets a socket timeout or expired API key

That error in #4 does not tell you anything about #2 or #3, and because execution spreads across everything in that process you have to check everything. If it was a thread, you would either not have the problem at all, it would show up clearly in request three, or you’d have a clear informative failure on a synchronization primitive saying that #3 held a lock for too long.

That makes it harder to control when memory is allocated or released in garbage collected languages, too, because you have to be very careful to trigger gc before doing something which can suspend execution for a while or you’ll get odd patterns when a small but non-zero percentage of those async requests take longer than expected (i.e. load image master, create derivative, send response needs care to release the first two steps before the last or you’ll have weird behavior when a slow client takes 5 minutes to finish transferring that response).

Arguably that’s something you want to do anyway but it dramatically undercuts the simplicity benefits of async code. I’m not saying that we should all give up async but there are definitely some pitfalls which many people stumble into.


Because async usually means you've stopped having "call stack" as a useful abstraction.

> Not all code written benefits from async nor even requires it. Running single threaded, sync programs is totally valid.

Maybe, but is it useful to have sync options?

You can still write single threaded programs


I mean single threaded + sync.

Sync options are useful. If everything is on the net probably less so. But if you have a couple of 1ms io ops that you want to get done asap, it's better to get them done asap.


> But if you have a couple of 1ms io ops that you want to get done asap, it's better to get them done asap.

and async prevents this how?


my statement was in response to "fs.readSync shouldn't exist". that is how.

if it didn't exist, the async version would still exist, which you could use to get it done asap

stop

doesn't a async runtime have more knowledge about the tasks than the OS about the threads?

Not the runtime per se, but cooperative scheduling has the advantage that tasks do not yield at adverse code points, e.g., right before giving up a lock, or performing an I/O request. Of course the lack of preemption has it's own downsides, but with thread-per-request you tend to run into tail latency issues much earlier than context switching overhead.

hardware from 10 years ago - do you have benchmarks for more recent hardware?

https://vorner.github.io/async-bench.html


I don't think those benches are much of a flex, even by the author's own description you'd be fine with any of them. They all have acceptable performance and don't show any order of magnitude differences or non-linear scaling problems.

Further, the benches that are showing best there are non-thread-stealing scenarios, not tokio.

I also suspect simply tuning the thread-based workloads more aggressively would have the same effect.

When I profile high throughput tokio applications there's way too much contention on shared atomics, mostly inside tokio's scheduler itself. On lower core count machines and where the workload is I/O heavy, this is probably fine. So, yes, web servers.

But I'm very interested in applications that scale on machines with lots of cores and where CPU is a large part of the equation.


You assumed

> Likely more efficient than half the async runtimes out there.

The benchmark shows the opposite: 2 (multithreaded async runtime) vs 7 (threads) * 10^8 ns per request for 2k requests/s.

> non-linear scaling problems.

oh, look closely, the relative gap increases with #requests/s


By TFA's own quote: "This means you probably shouldn’t put too much trust into the results I measured or base important decisions on the outcomes."

Your level of self-assured snark is way out of proportion to both the article and chart I'm looking at.

Props to the person who wrote the article. Your use of it however, is dubious.


It's more appropriate than your snarks based on no data

> If you are ten layers deep in a stack of synchronous functions and suddenly need to make an asynchronous call, the type signature of every individual function in the stack has to change.

well, this isn't really true - at least for Rust:

runtime.block_on(async{});

https://docs.rs/tokio/latest/tokio/runtime/struct.Handle.htm...


See my other post about the point. If you "just" turn an async back into a sync call by completely blocking the async scheduler, yes, you've turned the async call back into a sync call, but you've done that by completely eliminating async-ness. That's not a general solution. That is exactly what everyone back when Node was promoting this style spent paragraph upon paragraph warning you not to do, because it just punts by eliminating the asyncness entirely. "Async is great when you completely discard it" is not a winning argument for async... which is OK, because it's not the argument anyone is making.

> If you "just" turn an async back into a sync call by completely blocking the async scheduler,

I am not doing that. The caller (which is the only one being blocked here) is sync anyways and just wants to call an async function, so no async scheduler is blocked.


In Kotlin, it’s runBlocking {<asynchronous-code>}.

This is a language specific problem, not a language pattern one.


Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: