-
-
Notifications
You must be signed in to change notification settings - Fork 722
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
Async inTransaction()
and inDatabase()
#76
Comments
Hello @cfilipov,
Here is an extension that you can reuse: extension DatabaseQueue {
func asyncInDatabase(_ block: (Database) -> ()) {
DispatchQueue.global(attributes: [.qosDefault]).async {
self.inDatabase(block)
}
}
} asyncInTransaction can't be written this way because of commit/rollback error handling (that's why inTransaction() is
GRDB is sync by default because:
Now you know why sync accesses to the database is the default, and will remain so. |
This thread gives more context for async access in FMDB. Quoting @robertmryan:
It could have been written by you, @cfilipov :-) I don't follow this argument: inDatabase/inTransaction are not regular potentially long-running methods which return a result. They run an application closure, with the pitfalls I have listed above. Last, the problem I see with ccgus/fmdb#469 (which adds async transactions to FMDB) is that transaction errors are not handled. FMDB makes it very easy to overlook database errors, and I think that's why this PR looks so nice at first sight. |
Hey, watching the WWDC conferences is always interesting. GCD in Swift 3 brings a (synchronous) pearl: extension DispatchQueue {
public func sync<T>(execute work: @noescape () throws -> T) rethrows -> T
} Doesn't look wonderful at 1st sight, hu? Well, what's new is dbQueue.inDatabase { db in
favoritePois = PointOfInterest.fetchAll(db) // No need for `self.`
} Update your Swift3 branch! |
I have this extension already. I was pointing out that it seems to be a common case to use it, such that everyone would end up implementing it, so it should probably be part of GRDB itself.
Which would be yet another level of nesting. My point is that we're forced into one extra layer of nesting we don't need. Of course the extension
This is a good argument for keeping the sync api (and also keeping it the default), but not a good argument for excluding the async api.
I don't understand how they can not be considered long-running. These are apis for hitting a database. By definition they are likely to do I/O (if it's not an in-memory DB) and processing of the data. In all but the most trivial cases inDatabase/inTransaction will possibly block long enough to have an effect on the UI. Any app doing any real queries will inevitably have to dispatch to a background queue like they would for network requests. |
True. But the extension is trivial to add, I like my menus to be short (less documentation to write, less mental overhead for the documentation reader), and an equivalent asyncInTransaction can not be written (and I like symmetry).
Of course they can be long running, @cfilipov. |
It has been a long wait, but asynchronous database access methods (#550) will ship with GRDB 4.1 :-) |
Documentation states that
inTransaction()
andinDatabase()
(and the database pool equivalents) block the current thread. But if you have an expensive query (or a big write) you probably don't want to block the main thread so you would want to dispatch async onto a background thread.This ends up requiring a lot of nesting. One thing I found myself doing is extending
DatabaseQueue
so I could do this:Under the hood
inTransaction()
andinDatabase()
useperformSync()
and I notice that you already have aperformAsync()
method but onlyDatabasePool.readFromWrite()
uses it. I don't need a database pool though. I'm not trying to achieve concurrent reads, I just want to avoid blocking the main thread (also the database pool is still synchronous when writing).This seems like it would be a common enough scenario that
asyncInDatabase()
andasyncInTransaction()
should be part of GRDB. In fact, I think it's so common to create a thread to async your database calls thatinTransaction()
andinDatabase()
should be async by default and the synchronous versions should be the special cases:syncInTransaction()
andsyncInDatabase()
.Thoughts?
The text was updated successfully, but these errors were encountered: