objectbox / objectbox-dart

Flutter database for super-fast Dart object persistence
https://docs.objectbox.io/getting-started
Apache License 2.0
918 stars 116 forks source link

[Flutter] Async methods working significantly slower than the Sync methods. #576

Closed huseyin-kucuksahin closed 5 months ago

huseyin-kucuksahin commented 6 months ago

Build info

Description

There is a list view in the page that can be refreshed. Everytime I refresh the list first its being requested from objectbox trought my generic repository, then from service etc...

I've realized that sometimes the code waiting absurd times for data to be readed. First I thought thats the service but after debuging and measuring, realized the getAllAsync() method returns the data very slowly. After that I've switched to sync version 'getAll()' method. Now there is no problem, its spends around 0.002 sec to get the data. The thing is why the async method spends up to 2(?) solid seconds for only 0.002 sec job?

Test of SYNC

Here is the code from my repository and the result logs:

Sync Code ```dart Future> getAll() async { try { var stopwatch = Stopwatch()..start(); var store = await getStore(); Log.info('[STOPWATCH] Store get time: ${stopwatch.elapsed}'); var entities = store.box().getAll(); Log.info('[STOPWATCH] Database result time: ${stopwatch.elapsed}'); return entities; } on Exception catch (e) { Log.error('GetAll error.', error: e); } return const []; } ```
Result ![image](https://github.com/objectbox/objectbox-dart/assets/29236412/c276d58b-a881-4dc0-999e-9ca675c0597b)

Test of ASYNC

Now when you switched to the async version and do the same thing. Code will be like,

Async Code ```dart Future> getAll() async { try { var stopwatch = Stopwatch()..start(); var store = await getStore(); Log.info('[STOPWATCH] Store get time: ${stopwatch.elapsed}'); var entities = await store.box().getAllAsync(); Log.info('[STOPWATCH] Database result time: ${stopwatch.elapsed}'); return entities; } on Exception catch (e) { Log.error('Delete error.', error: e); } return const []; } ```
Result ![image](https://github.com/objectbox/objectbox-dart/assets/29236412/53c06076-2787-46f0-a6f8-337a08db8e3b)

It might be doesn't look like a problem with this results, but in some cases that I couldn't find it spents almost 12 seconds to get only 5 objects that has 15 parameters. Its a very small data yet a very long wait.

Code

Here is the entity class:

Entity Note: The CardModel is a freezed model thats not related with this situation ```dart @Entity() class CardEntity implements IObjectboxEntity { @override @Id(assignable: true) int entityId = 0; String no; String typeName; String typeId; double lastBalance; double subscriptionFee; String? date; String? holderId; String? holderName; String? cardName; bool stillValid; // Card balance data @Property(type: PropertyType.date) DateTime? subscriptionEndDate; String? subscriptionType; String? subscriptionCount; double? topUpBalance; double? finalBalance; CardEntity( this.no, this.typeName, this.typeId, this.lastBalance, this.subscriptionFee, this.date, this.holderId, this.holderName, this.cardName, this.stillValid, this.subscriptionEndDate, this.subscriptionType, this.subscriptionCount, this.topUpBalance, this.finalBalance, ); CardEntity.fromModel(CardModel model) : entityId = int.parse(model.cardNo), no = model.cardNo, typeName = model.typeName, typeId = model.typeId, lastBalance = model.lastBalance, subscriptionFee = model.subscriptionFee, date = model.date, holderId= model.holderId, holderName = model.holderName, cardName = model.cardName, stillValid = model.stillValid, subscriptionEndDate = model.subscriptionEndDate, subscriptionType = model.subscriptionType, subscriptionCount = model.subscriptionCount, topUpBalance = model.topUpBalance, finalBalance = model.finalBalance; @override CardModel toModel() => CardModel( cardNo: no, typeName: typeName, typeId: typeId, lastBalance: lastBalance, subscriptionFee: subscriptionFee, date: date, holderId: holderId, holderName: holderName, cardName: cardName, stillValid: stillValid, subscriptionEndDate: subscriptionEndDate, subscriptionType: subscriptionType, subscriptionCount: subscriptionCount, topUpBalance: topUpBalance, finalBalance: finalBalance, ); } ```

Here is the abstract class I use:

IObjectboxEntity ```dart abstract class IObjectboxEntity extends IEntity { int entityId = 0; TModel toModel(); } ```

Note

This tests happen in the debug mode build that runs in a physcal device. The release mode can be faster or maybe its not even a something to worry about. Maybe some debugging tools makes the threads busy that objectbox waiting for them? I just want to know why the results are wierd like this.

vamsikrishnacse commented 6 months ago

Hi @Destanci, i would like to work on this task! is this the work flow you are expecting from async method to do?

getAll() method called Stopwatch started getStore() awaited [STOPWATCH] Store get time: X milliseconds getAllAsync() awaited [STOPWATCH] Database result time: Y milliseconds getAll() method completed

huseyin-kucuksahin commented 6 months ago

method is just fine with sync or async doesnt really matters. My question is, is there anything wrong with the async functions? no? then why it tooks 100times more time to get the data with async?

vamsikrishnacse commented 6 months ago

When i see the code Async the code line var entities = await store.box().getAllAsync(); is using await function which will wait until it gets the result and i thing you are using getall() function in async code pls check. I may be wrong! this may be a solution for the entities variable await usage:

var entitiesFuture = store.box<TEntity>().getAllAsync();

// Perform other tasks while waiting for getAllAsync to complete.

// Now, await the result of getAllAsync when needed.
var entities = await entitiesFuture;
huseyin-kucuksahin commented 6 months ago

nah, measured the time outside of the function too. changing the position of awaiting does not make sense at all. since if you didnt start to await that Future wont start working right?. Also nothing else to do between that 2 lines.

greenrobot-team commented 5 months ago

@Destanci As documented, the async methods spawn a worker isolate to complete the box operation. That naturally takes some more time than directly calling the database API.

However, 2 seconds vs. 2 microseconds seem rather long. As you mentioned it, did you test in release mode? This is where we also measure performance and did not find that much of a penalty for using the async variants.

Note: @vamsikrishnacse is not associated with ObjectBox. I've also hidden the comments of that discussion.

github-actions[bot] commented 5 months ago

Without additional information, we are unfortunately not sure how to resolve this issue. Therefore this issue has been automatically closed. Feel free to comment with additional details and we can re-open this issue.