5 ms·
Sounds so impressive, but as a game dev, how do you overcome these problems: 1. Horrible performance. Instead of for-loops you are wrapping code in ienumerable
by hacker_9 11y ago
Sounds so impressive, but as a game dev, how do you overcome these problems:
1. Horrible performance. Instead of for-loops you are wrapping code in ienumerables, yield returns, linq, and event handlers. This is not acceptable for game dev because of the constant freeze frames from the collection of all the garbage generated.
But how is this good for web dev either? You are either on the client using javascript which is already 200x slower than native, or on the backend where you could be dealing with 10s of 1000s requests at any moment so saving memory/performance is a priority.
2. 'Subscribe' methods makes behavior hard to pin down. Whenever i see an event in the code, i now have to assume there could be a subscription at some point at runtime. All I have for this is Ctrl+F search my codebase. Or write a boatload of tests to make sure someone doesn't subscribe something somewhere wrongly.
This creates a debugging nightmare. The more generic/dynamic code the more you can't see what's going on. Irony of an 'observable' is I can't observe it until I'm running my code which is too late.
3. Streams of data: to be fair, this is a nice feature. I've used it myself to flatten a tree and read as a list for example, where the reader would yield return a struct item { type=node|indent|dedent, node }. It's also nice to read and modify code like this, and quicker to refactor. But it is still wayy slower - your basically wrapping 'if statements' into 'filter(x => ...)' linq objects. The compiler can't optimise this stuff for branch prediction, not to mention the intermediate lists that are created, so for the readability you are losing soo much performance it's just not worth it. If there was a language that could compile down these streams into loops/ifs etc that could be a real win though.
- pjmlp 11y agoOnce upon a time I used to argue about using jump vs call/ret due to execution cycles. Or adding nop opcodes to improve instruction fetching. A few years later I used to argue about direct function calls vs VMT lookups. Once upon a time I used to DW for the whole block I was using. Then came NEW/DISPOSE. Nowadays I only care when the profiler tells me todo so. I imagine you see where I am getting to.
- RyanZAG 11y agoAgreed in general, but it's also the level of inefficiency that matters. In the case of jump vs call/ret and those others, you're looking at a less-than-double increase in time. It's there and you can optimize it, but if you don't you don't really notice. FRP can be very different. With a large chunk of data and the wrong methods, you could be copying and re-copying that data over and over instead of editing it in place. This isn't just a 100% slowdown - you can go from 5 seconds to 500 seconds when converting an in-place data modification to FRP. Basically O(n) vs O(2n) ? Optimize it later if necessary O(n) vs O(n^3) - Uh oh! That's not to say that FRP is bad or you shouldn't use it, but never use a 'magic' mapping in FRP unless you know exactly what it is doing to the data and if it's going to copy or not (hint: it usually is).
- vitalyd 11y agoYou're getting to performance left on the table. Unfortunately, java and the existing JVM jit compilers will not fold away all the abstractions (nevermind the allocations if you have capturing lambdas). Whether this matters is circumstantial, but for serious game dev it most definitely will.
- eurekin 11y agoHi! I have thought about the same issues as you described. I see this as an interaction between two parties: producer and consumer. If the producer is so slow, that the consumer manages to ask 1000s of times for a product before it's created, than we have a case for reactive events. Game programming is different: the rate at which the events are produced greatly overwhelm the consumer rate (60 fps is nice target for graphics). There is one exception though! I have found a very annoying issue in a lot of games: they sometimes drop input. If you happen to play some fast action game and the game is crunching too much for the moment and drops FPS, also assuming that input events are polled once per frame, then a lot of input events might go unnoticed. Only the last input state for one frame is recognized by the game logic, but there might have been more than one. So, in my opinion, input handling would be better handled in a pull fashion, where all the events could be processed immediately, for example: the rotation matrix could be updated off the game loop many times between one frame. I hate all those 3d viewers which loose all interactivity if the scene is too large. It doesn't have to be!
- hacker_9 11y agoI'm afraid you would just be moving the problem to another area of the game. By updating the camera matrices on a separate loop, the render thread may draw some objects with one view-proj and then the last few objects with another. This would lead to the objects look like they are flickering. If you queued up the input then you could imagine this would be quite undesirable if the game suddenly unfroze and did all the movements that made sense a second ago but not now (but for a 3d viewer tool this would be desirable, much like how a text editor will sometimes freeze but then catch up with everything you typed during the pause).
- eurekin 11y agoI wouldn't update the view matrix directly. Rather let the input events update one matrix and the game loop would copy it only once per frame. This way all the input events would be summarized in that matrix and the view would follow the dragging cursor, even at 3FPS. So, many input events are seen as a summarized version in the game loop. Not many of them.