Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Commands::insert_batch #8384

Closed
wzjsun opened this issue Apr 14, 2023 · 3 comments · Fixed by #15702 · May be fixed by #8600
Closed

Add Commands::insert_batch #8384

wzjsun opened this issue Apr 14, 2023 · 3 comments · Fixed by #15702 · May be fixed by #8600
Labels
A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible C-Performance A change motivated by improving speed, memory usage or compile times

Comments

@wzjsun
Copy link

wzjsun commented Apr 14, 2023

What problem does this solve or what need does it fill?

Creating multiple entities of the same prototype in the system is a very common requirement, and existing Commands::spawn_batch can create entities in bulk and achieve efficient insertion, but this interface cannot return the Enity I have already created. If I need these entities, I have adopted the following method:

let mut entity_ list = Vec::new();

let mut bundle_ list= Vec::new();
for _ in 0..100 {
  let entity = commands.spawn_ empty();
  entity_ list.push(entity);
  bundle_ list.push((entity, Bundle))
}
commands.insert_ or_ spawn_ batch(bundle_list.into_iter());

But I encountered a very serious performance issue, some entities may need to check if they are in pending , and this inspection will go through an iterative process, and the code snippet is:

else if let Some(index) = self.pending.iter().position(|item| *item == entity.index) {
  self.pending.swap_ remove(index);
  let new_ free_ cursor = self.pending.len() as IdCursor;
  *self.free_ cursor.get_ mut() = new_ free_ cursor;
  self.len += 1;
  AllocAtWithoutReplacement::DidNotExist
}

This approach is slower than inserting one at a time

What solution would you like?

Add Commands::insert_batch, but do not check if each entity is in pending, panic If the entity does not exist.

@wzjsun wzjsun added C-Feature A new feature, making something new possible S-Needs-Triage This issue needs to be labelled labels Apr 14, 2023
@nicopap nicopap added A-ECS Entities, components, systems, and events C-Performance A change motivated by improving speed, memory usage or compile times and removed S-Needs-Triage This issue needs to be labelled labels Apr 24, 2023
@Connor-McMillin
Copy link
Contributor

Connor-McMillin commented May 12, 2023

I see there is also World::insert_or_spawn_batch, should a similar thing be done there?

Edit: Just saw that Command::insert_or_spawn_batch calls World::insert_or_spawn_batch

@Connor-McMillin
Copy link
Contributor

I made a draft PR that I think addresses the issue. @wzjsun or @nicopap let me know if this solution is in line with what you're expecting

@wzjsun
Copy link
Author

wzjsun commented Aug 7, 2023

@Connor-McMillin Thank you for reaching out. I'm pleased to inform you that my requirements have been met. I greatly appreciate the effort you have put into addressing this issue.

github-merge-queue bot pushed a commit that referenced this issue Oct 13, 2024
# Objective

`insert_or_spawn_batch` exists, but a version for just inserting doesn't
- Closes #2693 
- Closes #8384 
- Adopts/supersedes #8600 

## Solution

Add `insert_batch`, along with the most common `insert` variations:
- `World::insert_batch`
- `World::insert_batch_if_new`
- `World::try_insert_batch`
- `World::try_insert_batch_if_new`
- `Commands::insert_batch`
- `Commands::insert_batch_if_new`
- `Commands::try_insert_batch`
- `Commands::try_insert_batch_if_new`

## Testing

Added tests, and added a benchmark for `insert_batch`.
Performance is slightly better than `insert_or_spawn_batch` when only
inserting:


![Code_HPnUN0QeWe](https://github.com/user-attachments/assets/53091e4f-6518-43f4-a63f-ae57d5470c66)

<details>
<summary>old benchmark</summary>

This was before reworking it to remove the `UnsafeWorldCell`:


![Code_QhXJb8sjlJ](https://github.com/user-attachments/assets/1061e2a7-a521-48e1-a799-1b6b8d1c0b93)
</details>

---

## Showcase

Usage is the same as `insert_or_spawn_batch`:
```
use bevy_ecs::{entity::Entity, world::World, component::Component};
#[derive(Component)]
struct A(&'static str);
#[derive(Component, PartialEq, Debug)]
struct B(f32);

let mut world = World::new();
let entity_a = world.spawn_empty().id();
let entity_b = world.spawn_empty().id();
world.insert_batch([
    (entity_a, (A("a"), B(0.0))),
    (entity_b, (A("b"), B(1.0))),
]);

assert_eq!(world.get::<B>(entity_a), Some(&B(0.0)));

```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible C-Performance A change motivated by improving speed, memory usage or compile times
Projects
None yet
3 participants