ID:1904940
 
Applies to:Dream Daemon
Status: Open

Issue hasn't been assigned a status value.
Really, getting a working system in place to handle threading and object locks is a step in the right direction to modernizing the byond platform.

Unless graphene finds a way to make it out of lab, we've basically hit a limitation on single core performance, and that will remain the case until optronics takes off and processors use light, not electricity for their inners, 5 to 10 years down the line. (This should be a fun time, when processors jump from the ghz range to the thz range practically overnight).

So at some point, threading in the language will be an inevitability, to get there, the following path should happen:

Basic threading of internal operations, map thread/DD gui.
This will lead to some sort of threading framework being developed

Moving spawn() from a "Multiple Stack, Single Thread" system to "Multiple Thread, Single Execution" system (basically, make spawn() make new threads, but only allow one to run at any given time, to offload the transfer of stack info to the kernal, and take advantage of HT systems in intel processors to basically remove almost all overhead from spawn())
This is more designed to allow for the development of a framework for handling threading within game code.

Finally, Make fork() in game code. Along with a system for handling object locks, implementation of some publicly known lock contention solution, etc.

fork() doesn't have to be user friendly, it's ok for a engine like byond to have a section of features that's for advanced projects.

The end goal is to ensure byond is a good system for new programmers, and reminds viable for when those new programmers make games that grow up and get more needy. (ss13 is so many levels of a good example of this, It wouldn't have existed without byond making it easy to make, but now it's all grown up.)
The threading experiment was pulled off the table and remains so for now. It was really disastrous and I'm not sure how feasible it will ever be to bring it back, but I'm at least open to trying at some point.

Multi-threading actual procs will never be possible as far as I can see. Proc code uses calls that would run into huge concurrency issues across the board. For instance, consider setting an icon_state on an appearance. That creates a new appearance (potentially) and may need to make some allocations. Even if it doesn't, the very lookup process for appearances would have to be protected against alterations. And this sort of thing happens everywhere; string manipulation, for instance, would be nightmarish. The core design is simply too unfriendly to threading where it comes to running the interpreted code. Sending maps was easier to thread (though not without its headaches) because not a lot of shared info changed during that process.

If I follow your idea right of only allowing one thread to run at a time, that at least could possibly be done, but 1) it's way out of sync with anything even the existing thread code does, and 2) I don't see how it solves the single-core problem since bouncing from one core to the next and only running one at a time is no better.

Setting up locks and whatnot to support proper threading is very problematic. That'd represent a huge performance hit for each mutex it would use, and it'd be jumping in and out of critical sections left and right. About the only place you could avoid hitting such critical sections would be during basic operations, like adding numbers together using only local proc vars. Everything else would be fraught with concurrency problems.

As for fork(), I don't see that being possible at all. fork() is not available on Windows platforms, and the nearest workarounds are known to be flaky.
If I follow your idea right of only allowing one thread to run at a time, that at least could possibly be done, but 1) it's way out of sync with anything even the existing thread code does, and 2) I don't see how it solves the single-core problem since bouncing from one core to the next and only running one at a time is no better.

In order to start running something spawned, you have to do certain setup operations right? Bouncing around spawned procs has a enough of an inefficiency, that we removed it from the master controller (it was used to prevent sleeps in the callstack from halting the controller) and just found each of those sleeps and converted them to spawns or a combo of both, so that most processing atoms didn't need a spawn.

I wasn't around in tgstation for that, But when i suggested adding spawn to the mastercontroller, I was told that it used to have it and removing it reduced the latency caused by having lots of active objects.

If spawn() used its own thread, and you just managed the thread's resting state, literally all of that inefficacy goes away, an HT enabled processor can switch threads in as little as 2 processor cycles.

But it was more designed to be used as a stepping stone to actual threading.

Each of my suggestion was designed as a step to help build a threading solution for in language threading, they don't make much sense if that isn't the end goal. (I still think it's doable, but how the inners of byond work need to be simplified to make it doable)

As for fork(), I don't see that being possible at all. fork() is not available on Windows platforms

I meant as a byond language function. basically spawn but runs the thread concurrently.
In order to start running something spawned, you have to do certain setup operations right? Bouncing around spawned procs has a enough of an inefficiency, that we removed it from the master controller (it was used to prevent sleeps in the callstack from halting the controller) and just found each of those sleeps and converted them to spawns or a combo of both, so that most processing atoms didn't need a spawn.

My understanding is that it duplicates information from the current call stack, which includes local variables.

spawned code really only needs to keep track of the bytecode offset where the spawn will enter, because as long as you have the local memory duplicated it is functionally no different than any other proc that's been delayed.