stride3d / stride

Stride (formerly Xenko), a free and open-source cross-platform C# game engine.
https://stride3d.net
MIT License
6.58k stars 950 forks source link

Script and Task improvements Epic #20

Open xen2 opened 6 years ago

xen2 commented 6 years ago

Various ideas this Epic covers:

velhaco20000 commented 5 years ago

Is there anyone working on this task ?

velhaco20000 commented 5 years ago

You proposed 2 features:

Is that right ?

xen2 commented 5 years ago

Yes, that's two separate features (probably done together in the same feature branch). I started some prototyping on this task: https://github.com/xen2/xenko/tree/microthread2 I have made a simple library to test part of the concepts, next step is to decide exactly how to integrate it into Xenko and switch various part of Xenko to use it.

velhaco20000 commented 5 years ago

Do you want to create a mini batch system ?

velhaco20000 commented 5 years ago

I will read the code and make a proposal.

xen2 commented 5 years ago

FYI the code is still a prototype/playground, it is not yet integrated and lot of things will change.

velhaco20000 commented 5 years ago

Just a little update, and correct me if I'm wrong :

velhaco20000 commented 5 years ago

Little Update 2: (correct me if I'm wrong)

Let me hear your observations and corrections.

velhaco20000 commented 5 years ago

Little Update 3: ( corrections and observations are welcome)

velhaco20000 commented 5 years ago

Little Update 4:

fdrobidoux commented 5 years ago

@velhaco20000 I would suggest you make a draft pull request to a new branch based on master from a fork of this repo and talk about that over there. This is mostly to reduce spam on epics, and you'll be able to explain yourself better using the PR template.

velhaco20000 commented 5 years ago

@fdrobidoux , you are right. I just don't want to create something useless or something somebody else is doing right now.

HeadClot commented 4 years ago

Hey @xen2 - got a question about this Epic what do you mean by a "high-level sync point graph editor"? Do you mean visual Scripting because that would be nice to get. :)

CodingMadness commented 3 years ago

Has anything happend anymore in regard of this topic since i see that the tasks in stride 4.0.01 are still .NET 4.0 tasks and nott valuetasks afaik.

tebjan commented 3 years ago

@Shpendicus did you check the changes in the linked WIP branch?

CodingMadness commented 3 years ago

@tebjan what is WIP branch? where can i check it out?

Do u mean this one? https://github.com/xen2/stride/tree/microthread2

but isnt this more or less depricated and replaced now officially by stride?

MechWarrior99 commented 2 years ago

There was some further discussion on Discord about this topic and this is a summery of it. (@Eideren helped write a lot of this summery)

Rename "Script" (ScriptSystem, SyncScript, etc.) to be more fitting and intuitive. Additionally, the world "script" can be used to refer to other things such as files, and so can cause confusion. Current suggestions are:

Condense StartScript, SyncScript, and AsyncScript, and perhaps ScriptComponent in to a single component to simplify and streamline the API.

Change the implementation to allow for more flexibility and extensibility. These are the current ideas.

manio143 commented 2 years ago

Another thing that came to my head - we should consider if the current way of having scripts directly attached to entities is the way to go forward. Currently scripts may a bit too universal - it's easy to misuse them instead of using a pair component+processor. I think it would be nice to see a new entry point into the scene where beefier and usually single instance objects would be registered for execution and if they need to be tied to a single entity's lifetime, maybe we could leverage cancellation tokens that would be cancelled when an entity is removed from the scene. The second thing to keep in mind is to promote asynchronous code with good "wait for event" APIs - wait for input combination, wait for a physics event, rather than wait for every frame and check something.

ericwj commented 2 years ago

The AsyncScript should remain separate, although it could receive a similar renaming and a move to ValueTask. Having callbacks mixed with async is probably not the way to entice people to write the recommended code style. If instead of listening for callbacks people can await all the events they need, the resulting code will be much easier to write, read and debug.

No need to touch cancellation tokens and whatnot in the one callback to affect some other methods execution flow, in the process having to define all sorts of random fields to keep track of things which suddenly need to be accessible in multiple places, etc. And you'll find people unaware that they gave away half of the performance they won by using async due to that one high-frequency callback that they still have.

MechWarrior99 commented 2 years ago

I think it would be nice to see a new entry point into the scene where beefier and usually single instance objects would be registered for execution and if they need to be tied to a single entity's lifetime

Do you mean like a scene-level/'global' system for managers and systems, where you will only have a single instance of them? Things where you wouldn't need a entity for it? (An example could be a system that spawns enemies in the scene) If that is not, then can you explain more? If so, then I was actually also thinking just the other day how that could be a good idea. How would you see this changing the design of the current implementation though?

wait for input combination, wait for a physics event, rather than wait for every frame and check something.

Genuine question, how would the performance differ from this approach, apposed to one where certain methods are called when those events happen, or events are invoked? And would you say the wait approach is a nicer design?

MechWarrior99 commented 2 years ago

The AsyncScript should remain separate, although it could receive a similar renaming and a move to ValueTask

It would be needlessly redundant in my opinion. If we go with say the interface implementation, simply having a IAsyncExecute interface would have the same end result, while being cohesive with the rest of the system.

ericwj commented 2 years ago

simply having a IAsyncExecute interface would have the same end result

Async is much more than just an interface. Its a style of coding. Mixing the two yields spagetthi. Or worse, async over sync over async, deadlocks, and crashes. There's many excellent articles on this by Stephen Toub on devblogs.microsoft.com.

manio143 commented 2 years ago

Do you mean like a scene-level/'global' system for managers and systems, where you will only have a single instance of them? Things where you wouldn't need a entity for it? (An example could be a system that spawns enemies in the scene)

Yes, exactly something like that. Currently I'd either create a script and place an otherwise unused entity in the scene to hold a reference to it, or I need to implement a GameSystem, register it with the game class and potentially do some additional wiring to have it interact with the scene. With the task system we could have multiple representations of task sources - i.e. a component placed on an entity, a one off task executed on the game thread by another thread (think dispatcher of UI frameworks), a scene procedure invoked when a scene is activated (added as root or added as a subscene to an active scene) - this of course would mean extending the scene asset, which needs to be done with care.

(regarding async wait for event) how would the performance differ from this approach, apposed to one where certain methods are called when those events happen, or events are invoked? And would you say the wait approach is a nicer design?

The performance of a virtual method call directly is one thing, but currently we have a scheduler such that all callbacks of script methods happen in the same moment of a frame (sequentially, ordered by priority) - this adds some overhead but may allow additional robustness (it'd would be great to document Stride.Core.MicroThreading in greater detail first to understand it better). I imagine the main benefit of the async/await pattern is context persistence - rather than manually managing a state machine and fields of my object with single method callbacks I can first await one event, then await a new frame, modify some entity, await a different event and throughout all that any context will be captured and the compiler will do all the heavy lifting, leaving me with a nice looking sequential logic, that would otherwise be spread across multiple callbacks.

ericwj commented 2 years ago

(regarding async wait for event) how would the performance differ from this approach

The performance difference is in the amount of callbacks required as well, since the callback will in the synchronous case always be called for a class of event, even if you aren't actually interested in the specific one happening - for example you collide and you asked to be notified, but the current collission is with something you don't care about.

In the async model it would be fairly easy to specify in detail what events you care about at that particular place in the code and there will be no callback until the actual event you care about occurs. It won't be easy to optimize this to the fullest, but the end result could be close to simply never having to filter anymore - if the physics engine reports an event, exactly the right callbacks would then be instantly known from the carefully crafted context.

An additional benefit automatically obtained is that the priorities of callbacks are much less relevant, because callbacks happen much more seldomly, at different times, so there will be less sorting and generally a faster task system.

timcassell commented 6 months ago
  • Make our task system alloc-free (possible with recent C# version) so that people are not afraid to create thousands of scripts with await

Might you be interested in adopting ProtoPromise? Benchmarks show it to be the most efficient alloc-free async library.

CodingMadness commented 6 months ago
  • Make our task system alloc-free (possible with recent C# version) so that people are not afraid to create thousands of scripts with await

Might you be interested in adopting ProtoPromise? Benchmarks show it to be the most efficient alloc-free async library.

Looks very good, an implementation within the Engine could be smth, what do you guys say?

IXLLEGACYIXL commented 6 months ago
  • Make our task system alloc-free (possible with recent C# version) so that people are not afraid to create thousands of scripts with await

Might you be interested in adopting ProtoPromise? Benchmarks show it to be the most efficient alloc-free async library.

as its your library, it would make sense that you write a prototype of an integration and showing the advantages/disadvantages of what is existing currently vs your thing

you can make a WIP PR to let us see the progress

its the same with BEPU, nicogo made a showcase of the integration and showed the advantages and all were in the "lets goo" mood :D