HN user

quietbritishjim

7,895 karma
Posts0
Comments2,198
View on HN
No posts found.

No.

The article suggests using 8 bits (=256 values) to pack 5 trits (=243 values).

If you use 16 bits (=65536 values) then you can pack at most 10 whole trits (=59049 values). 11 trits (=177147 values) won't fit.

The current top comment, by JoshTriplett, analyses what you would need to beat the efficiency.

In Python Trio, you would have a thread pool for each type of computation (potentially a "pool" of 1 thread shared between all tasks if that works for your application). You would await trio.to_thread.run_sync(...) [1] (pass it a normal non-async function, and a token representing the thread pool). This is a pretty simple wrapper that takes care of queuing the work to the thread pool, waiting for it to complete and for a message to be passed back to the Trio thread.

It works for simple situations. It certainly preserves backpressure, although a slow CPU task can impact other users of the same thread pool.

[1] https://trio.readthedocs.io/en/stable/reference-core.html#tr...

Male lions don't hunt, females do. In human hunter gatherer society, it's the males that hunt while females gather plants.

Also, as I mentioned in a sibling comment, humans hunt in a fundamentally different way to most predators, including lions: humans chase to exhaustion over hours while lions try to outrun their prey over minutes or less. (That's why humans have three gaits: walking, jogging, running, while most animals only have walking and running.)

Well that's a purely intellectual question, given that empirical data on human hunter gatherers.

But I'd guess it's because (1) humans aren't purely predators, we're have a mixed diet with plants too, and (2) humans hint in a fundamentally different way to most predators, by chasing their prey to exhaustion over several hours rather than outrunning them over a few minutes.

There's also the range based for loop in C++. An actual comparison of iterator-style loops might be interesting but this article is a pretty vacuous bit of basic Python.

It's also a confusing title, given that Scratch is the name of a programming language.

Do you think our ancestors slept exactly 8 hours a night from 10pm to 6am?

Yeah I pretty much do expect that (but more like 6 or 7). They were awake a few hours after sunset by fire light, then get up fairly early. I certainly don't imagine them napping during the day, when they could be working together to get food, unless it's a climate where it's too hot to do anything in the middle of the day.

Studies of modern hunter gatherers seem to back this up e.g. [1]

It's widely known that Victorians would have two sleeps over night, with a productive period in the middle, but this seems to be a misconception based on a passing remark in one court case. Even if true, this is a post-industrial society with unhealthily long working hours and I don't think we should be copying their sleep patterns.

[1] https://www.sciencedirect.com/science/article/pii/S096098221...

This is a bit in the weeds but inside Google we static link everything which makes is far easier to do it, and static linking is how we recommend you use C++Proto in general.

Statically linking everything doesn't work in this case because each C extension module (i.e. each Python package with some native code in it) is, in effect, a shared library.

If you statically linked the C++ protobuf library into both the Python protobuf library and the Python tensorflow library then you'd end up with two copies of the library in the process (with two copies of globals/statics such as the protobuf global descriptor pool). That's not a problem in itself, but it wouldn't be possible to pass protobuf objects between them.

(In principle, you could perhaps statically link protobuf into the CPython executable, but I really don't think Google is doing that.)

The usual solution is the exact opposite to static linking: you have to build the C++ protobuf library as a shared library (libprotobuf.so) and then link to it from both of your C extension modules (i.e. from the other two shared libraries).

Following the tiny crumbs of evidence of how to do this for protobuf, it seems like that was previously how you would do it. But it's possibly not now? It seems like proto_api.h [1] has a way to get the global descriptor pool, possibly to work around needing a common shared library? But also now that header is deprecated anyway [2]? (I think this is roughly where I got to before when I gave up.)

[1] https://github.com/protocolbuffers/protobuf/blob/main/python...

[2] https://github.com/protocolbuffers/protobuf/issues/9464

If the original route was to continue on the current road, and the revised one is to come off, then you don't need to interact with the screen at all to reject it. Just continue driving, and the route will reset once you pass the exit.

If every road were free of traffic, every destination had unlimited parking at the door, everyone already owned a car, and driving carried no direct or indirect costs, almost everyone would drive everywhere.

Even with that unrealistically idealised scenario, if you had similarly idealised public transport (station within 5 minutes walk either end, trains every 5 minutes) I'd still choose the train much of the time. I could actually get something done on my laptop instead of having to concentrate on the road, plus I could get up for a stretch mid journey (without stopping). It would be different if I had a lot of luggage or was bringing the kids, though.

My point is that driving is not always inherently more attractive than public transport.

... that uses C++Proto as the in memory representation which libraries like TensorFlow can use to share memory between Python and C++

This is a valid explanation for the odd implementation of the Python protobuf library (the only convincing one I've heard). But, the last time I looked into it (just a couple of years ago), it didn't seem reasonably possible to make use of this.

I can't remember the exact issue I think maybe the C++ library would be statically linked into the Python C extension module, which made it virtually impossible to use it from your own C++ code. Or maybe the issue was just that there was no C++ version prebuilt on pypi (the default is the upb version).

Anyway, it seems a pity to go to such enormous lengths for one feature and then make it essentially unavailable.

Are the only two options SIMD in hand-rolled assembler and unbearably slow?

Often Python, with the most critical parts written in a compiled extension module (like this one), offers acceptable performance with enormously less complexity than writing the whole thing in a compiled language.

A great read even if you don't have a parent that has had severe failures.

My parents were loving and calm and, I found out later, one was very weird (I won't say more) with my older siblings but strangely never with me.

But I sometimes lose my temper with my young child (certainly not violent but I'm not proud of how I act), for reasons that feel very valid in the moment. This article is a helpful reminder to keep perspective.

there is no guarantee in the API that they both happen literally simultaneously

There's no actual guarantee in the API that if you spawn multiple threads and call blocking network I/O that those happen literally simultaneously. Maybe the OS has a big mutex on network I/O to serialise them.

Of course, that's not what happens in practice. But neither is it what happens, in practice, to async network APIs called concurrently in one thread. So I don't think that can be the difference between concurrent and parallel.

I would modify Stroustrup's rule like so:

* For new features, people insist on LOUD explicit syntax.

* For established features [that turned out to be used disproportionately often], people want terse notation.

So, I argue, it's not really people getting used to the feature that allows it to be terser. It's that enough time passes that you figure out what features are used enough that they warrant the terse syntax (like the Rust example he gave).

It's a form of selection bias: there are many other established features that are rarely used and left with a verbose syntax but you don't notice them later because, well, they're rarely used.

I'll admit I do really like that.

I still think it proves my point: your original objection was about the syntax being C-like and, as I predicted, the differences in syntax in your idea (where the type goes, colon vs positional, etc.) are all trivialities that don't affect usability.

What's better about your idea is that it's actual Python code rather than being embedded in a string. Maybe that was your point originally and I misunderstood.

Looks like this package works like this: https://harrymander.xyz/dataclasses-struct/

OK so what's your alternative then? It's easy to say you don't like something but the onus is on to show there's something actually better.

The library used in the author's post seems perfectly readable to me, enough that it didn't even register until I read your comment. Could it be tweaked slightly to not use C syntax? Sure, but it's still going to need roughly the same pattern of identifier + type (including size). Types in C are straightforward so long as you don't have functions/pointers (which have the "inside out" problem, but they're not needed for binary encodings), so you're going to be looking at pretty trivial changes to syntax. Certainly not enough to warrant this level of quibbling.

I asked an LLM to rewrite it for me using the Python built-in struct module, and it gave me this:

   import sys
   import struct
   from collections import namedtuple
   
   # Bake the layout once into a reusable, precompiled object.
   HEADER = struct.Struct(">4sIIIQQ16sQQIIII")
   
   # struct only knows positions, not names — pair it with a namedtuple
   # to recover the named-field access that cstruct gives you for free.
   Header = namedtuple("Header", [
       "magic", "field4", "field8", "fieldC",
       "field10", "field18", "field20",
       "field30", "field38",
       "field40", "field44", "field48", "field4C",
   ])
   
   with open(sys.argv[1], "rb") as fh:
       header = Header._make(HEADER.unpack(fh.read(HEADER.size)))
   
   print(header)
To me, this seems significantly less readable... less Pythonic, even. The printed output is also less readable.

The author clearly wasn't implying that these were 1GB chips. They just wanted to show a graph scaled per unit of memory. It could just as well have been per byte, and the graph would've been identical but the values on the left would be changed by a factor of a billion.

You could argue that you'd rather see a "price per typical-sized RAM chip as sold at the time". That would also be a perfectly valid thing to graph (though a bit more subjective), but it doesn't invalidate this one. Since per byte (or GB or whatever you want to say) has continued downward all this time, it makes the recent spike all the more notable.

(I'm not sure it's right to label vacuum tubes and core memory as "DRAM" though.)

If there was a year 0, we would still be in the 21st century. It would just have started 1 year earlier, in 2000 instead of 2001:

0 – 99: 1st century

100 – 199: 2nd century

...

1900 – 1999: 20th century

2000 – 2999: 21st century

Although I think centuries are usually treated as starting in years ending in 0 anyway, in casual settings. Most people were certainly happy to celebrate "the new millennium" at the start of the year 2000.

It's nothing inherent about Windows (not even one-click .exe files), it's existing programs and drivers that only run on Windows, which of course only run on Windows because it was already popular.

For me it's MS Office. Sorry, but OpenOffice.org and the Google apps still don't come close. (And of course Office file formats are their own lock in, very analogously to the programs that run on Windows.)

I'd suggest not adding recruiters as LinkedIn connections in the first place. I mean, LinkedIn is hardly sacred, but why are you adding people you don't know as a connection?

Recruiters only add you as a connection if they can't afford LinkedIn premium, which is what you need to message people you're not connected to (except for connection requests). That probably means that they're not very successful recruiters.