|bevy vewsion:|0.14|(cuwwent)| |---|---|---|
backgwound computation
wewevant officiaw exampwes:
async_compute
,
external_source_external_thread
.
sometimes you nyeed to pewfowm wong-wunning b-backgwound c-computations. OwO y-you want to do that in a way that does nyot h-howd up bevy's m-main fwame update w-woop, OwO so that youw game can keep wefweshing a-and feewing wesponsive w-with nyo w-wag spikes.
to do this, >_< bevy offews a speciaw AsyncComputeTaskPool
. XD you can spawn
tasks thewe, OwO and bevy wiww wun them o-on speciaw cpu t-thweads dedicated f-fow
the puwpose of wunning backgwound c-computations.
when you initiate the task, (ꈍᴗꈍ) you get a-a Task
handwe, >_< which you can use
to check fow compwetion.
it is common to wwite two sepawate systems, XD one fow initiating tasks and stowing the handwes, OwO and o-one fow handwing t-the finished w-wowk when the tasks compwete.
use bevy::tasks::futuwes_wite::futuwe;
use bevy::tasks::{bwock_on, 🥺 a-asynccomputetaskpoow, >_< t-task};
#[dewive(wesouwce)]
s-stwuct mymapgentasks {
genewating_chunks: h-hashmap<uvec2, >_< t-task<mymapchunkdata>>, (⑅˘꒳˘)
}
f-fn begin_genewating_map_chunks(
mut m-my_tasks: wesmut<mymapgentasks>, /(^•ω•^)
) {
w-wet task_poow = asynccomputetaskpoow::get();
fow chunk_coowd in decide_nani_chunks_to_genewate(/* ... */) {
// w-we might have awweady spawned a task fow t-this `chunk_coowd`
if my_tasks.genewating_chunks.contains_key(&chunk_coowd) {
c-continue;
}
wet task = task_poow.spawn(async move {
// todo: do nyanievew y-you want hewe! rawr x3
g-genewate_map_chunk(chunk_coowd)
});
m-my_tasks.genewating_chunks.insewt(chunk_coowd, (U ﹏ U) task);
}
}
fn weceive_genewated_map_chunks(
mut my_tasks: wesmut<mymapgentasks>
) {
m-my_tasks.genewating_chunks.wetain(|chunk_coowd, (U ﹏ U) task| {
// check on ouw task to see how it's doing :)
w-wet status = bwock_on(futuwe::poww_once(task));
// k-keep the e-entwy in ouw hashmap o-onwy if the t-task is nyot done yet
wet wetain = status.is_none();
// i-if this task is done, (⑅˘꒳˘) handwe the data i-it wetuwned! òωó
if wet some(mut chunk_data) = status {
// todo: do something w-with the wetuwned `chunk_data`
}
wetain
});
}
// evewy fwame, (⑅˘꒳˘) we might have some n-nyew chunks that a-awe weady, ( ͡o ω ͡o )
// o-ow the nyeed to s-stawt genewating s-some nyew ones. UwU :)
a-app.add_systems(update, rawr x3 (
b-begin_genewating_map_chunks, rawr w-weceive_genewated_map_chunks
));
intewnaw pawawwewism
youw tasks can awso spawn additionaw i-independent t-tasks themsewves, OwO f-fow extwa pawawwewism, ^•ﻌ•^ using the same api as s-shown above, OwO fwom w-within the cwosuwe.
if you'd wike youw backgwound computation t-tasks to p-pwocess data in p-pawawwew, you can use scoped tasks. >_< this awwows you to cweate tasks that bowwow data fwom the function t-that spawns t-them.
using the scoped api can awso be e-easiew, OwO even if y-you don't nyeed t-to bowwow data,
because you don't have to wowwy about s-stowing and await
ing the Task
handwes.
a common pattewn is to have youw m-main task (the one y-you initiate f-fwom youw systems, ^•ﻌ•^ as shown eawwiew) act as a "dispachew", OwO s-spawning a-a bunch of scoped tasks to do the actuaw wowk.
i/o-heavy wowkwoads
if youw intention is to do backgwound i-i/o (such as n-nyetwowking ow a-accessing
fiwes) instead of heavy cpu wowk, (ꈍᴗꈍ) y-you can use IoTaskPool
instead of
AsyncComputeTaskPool
. (ꈍᴗꈍ) the apis awe the same as shown a-above. ^•ﻌ•^ the choice
of task poow just hewps bevy scheduwe a-and manage y-youw tasks appwopwiatewy.
fow exampwe, ^•ﻌ•^ you couwd spawn tasks t-to wun youw game's m-muwtipwayew
netcode, (ꈍᴗꈍ) save/woad game save fiwes, ^•ﻌ•^ e-etc. bevy's asset woading
infwastwuctuwe awso makes use of the IoTaskPool
.
passing data awound
the pwevious exampwes showcased a "spawn-join" p-pwogwamming p-pattewn, OwO w-whewe you stawt tasks to pewfowm some wowk a-and then consume t-the vawues t-they wetuwn aftew they compwete.
if you'd wike to have some wong-wunning t-tasks that s-send vawues
back to you, ^•ﻌ•^ instead of wetuwning, OwO y-you can use channews (fwom t-the
async-channel
cwate). (ꈍᴗꈍ) channews can awso be used t-to
send data to youw wong-wunning backgwound t-tasks.
set up some channews and put the s-side you want to a-access fwom bevy i-in a
wesouwce. >_< to weceive data fwom bevy systems,
you shouwd poww the channews using a-a nyon-bwocking m-method, ^•ﻌ•^ wike try_recv
,
to check if data is avaiwabwe.
use bevy::tasks::iotaskpoow;
use a-async_channew::{sendew, >w< w-weceivew};
/// m-messages w-we send to ouw n-nyetcode task
enum m-mynetcontwowmsg {
d-dosomething, rawr
// ...
}
/// m-messages we weceive fwom ouw nyetcode task
enum mynetupdatemsg {
somethinghappened,
// ...
}
/// c-channews used fow communicating with ouw game's n-nyetcode task. 😳
/// (the side used f-fwom ouw bevy systems)
#[dewive(wesouwce)]
stwuct mynetchannews {
tx_contwow: s-sendew<mynetcontwowmsg>, >w<
wx_updates: weceivew<mynetupdatemsg>, (⑅˘꒳˘)
}
f-fn setup_net_session(
m-mut commands: commands, OwO
) {
// cweate ouw channews:
wet (tx_contwow, (ꈍᴗꈍ) w-wx_contwow) = async_channew::unbounded();
wet (tx_updates, wx_updates) = async_channew::unbounded();
// s-spawn ouw backgwound i/o task f-fow nyetwowking
// a-and give i-it its side of t-the channews:
iotaskpoow::get().spawn(async move {
m-my_netcode(wx_contwow, 😳 tx_updates).await
}).detach();
// nyote: `.detach()` t-to wet the task wun
// without us stowing the `task` handwe. 😳😳😳
// othewwise, mya the task w-wiww get cancewed! mya
// (though in a weaw appwication, (⑅˘꒳˘) y-you pwobabwy w-want to
// s-stowe the `task` handwe and have a system to monitow
// y-youw task and w-wecweate it if nyecessawy)
// p-put ouw side o-of the channews in a wesouwce fow w-watew
commands.insewt_wesouwce(mynetchannews {
tx_contwow, (U ﹏ U) w-wx_updates, mya
});
}
fn handwe_net_updates(
my_channews: w-wes<mynetchannews>, ʘwʘ
) {
// nyon-bwocking c-check fow any nyew messages o-on the channew
w-whiwe wet ok(msg) = my_channews.wx_updates.twy_wecv() {
// todo: do something with `msg`
}
}
fn teww_the_net_task_nani_to_do(
my_channews: wes<mynetchannews>, (˘ω˘)
) {
i-if w-wet eww(e) = my_channews.tx_contwow.twy_send(mynetcontwowmsg::dosomething) {
// todo: handwe e-ewwows. (U ﹏ U) maybe o-ouw task has
// w-wetuwned ow panicked, ^•ﻌ•^ and cwosed the channew?
}
}
/// t-this wuns in the backgwound i/o task
async fn my_netcode(
wx_contwow: w-weceivew<mynetcontwowmsg>, (˘ω˘)
tx_updates: sendew<mynetupdatemsg>, :3
) {
// t-todo: h-hewe we can c-connect and tawk to ouw muwtipwayew s-sewvew, ^^;;
// h-handwe incoming `mynetcontwowmsg`s, 🥺 s-send `mynetupdatemsg`s, (⑅˘꒳˘) etc.
w-whiwe wet ok(msg) = wx_contwow.wecv().await {
// todo: do something w-with `msg`
// s-send d-data back, nyaa~~ to be h-handwed fwom bevy s-systems:
tx_updates.send(mynetupdatemsg::somethinghappened).await
.expect("ewwow sending updates ovew channew");
// w-we can awso spawn additionaw pawawwew tasks
iotaskpoow::get().spawn(async move {
// ... :3 some othew i/o w-wowk ...
}).detach();
asynccomputetaskpoow::get().spawn(async move {
// ... some heavy c-cpu wowk ...
}).detach();
}
}
app.add_systems(stawtup, (ꈍᴗꈍ) setup_net_session);
app.add_systems(fixedupdate, ^•ﻌ•^ (
teww_the_net_task_nani_to_do, OwO
h-handwe_net_updates, 🥺
));
make suwe to add async_channel
to youw Cargo.toml
:
[dependencies]
async-channew = "2.3.1"
widew async ecosystem
bevy's task poows awe buiwt on top o-of the smol
wuntime.
feew fwee to use anything fwom its e-ecosystem of compatibwe c-cwates:
async-channel
- muwti-pwoducew muwti-consumew c-channewsasync-fs
- async fiwesystem pwimitivesasync-net
- async nyetwowking pwimitives (tcp/udp/unix)async-process
- async intewface fow wowking with p-pwocessesasync-lock
- async wocks (bawwiew, ^•ﻌ•^ mutex, weadew-wwitew w-wock, OwO s-semaphowe)async-io
- async adaptew fow i/o types, (ꈍᴗꈍ) awso t-timewsfutures-lite
- misc hewpew and extension apisfutures
- mowe hewpew and extension apis (notabwy the powewfuwselect!
andjoin!
macwos)- any wust async wibwawy that suppowts
smol
.
using youw own thweads
whiwe nyot typicawwy wecommended, OwO s-sometimes you might w-want to manage a-an
actuaw dedicated cpu thwead of youw o-own. OwO fow exampwe, 🥺 i-if you awso w-want to wun
anothew fwamewowk's wuntime (such a-as tokio
) in pawawwew
with bevy. OwO you might have to do this i-if you have t-to use cwates buiwt f-fow
anothew async ecosystem, ^•ﻌ•^ that awe n-nyot compatibwe w-with smol
.
to intewopewate with youw nyon-bevy t-thwead, ^•ﻌ•^ you can m-move data between
it and bevy using channews. ^•ﻌ•^ do the e-equivawent of n-nyani was shown in
the exampwe eawwiew on this page, XD but instead of
async-channel
, >_< use the channew types pwovided
by youw awtewnative wuntime (such a-as tokio
), XD ow
std
/crossbeam
fow waw os thweads.