[CSHARP-138] Add asynchronous APIs Created: 22/Dec/10 Updated: 09/Feb/15 Resolved: 03/Sep/14 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | 2.0 |
| Type: | New Feature | Priority: | Critical - P2 |
| Reporter: | Flavien | Assignee: | Craig Wilson |
| Resolution: | Duplicate | Votes: | 77 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Attachments: |
|
||||||||||||||||||||
| Issue Links: |
|
||||||||||||||||||||
| Epic Link: | New Client API | ||||||||||||||||||||
| Backwards Compatibility: | Minor Change | ||||||||||||||||||||
| Description |
|
C# 5.0 is all about making asynchronous programming a first class citizen of the language. Also, writing scalable server applications requires using only asynchronous I/O. This can only be done if the MongoDB driver exposes asynchronous operations for querying the database. In order to make it compatible with what C# 5.0 will be using, those APIs will need to use the task based pattern, and return Task<T>. public MongoCursor<TDefaultDocument> Find(IMongoQuery query) would have an asynchronous equivalent: public Task<MongoCursor<TDefaultDocument>> FindAsync(IMongoQuery query) The resulting task represents a token for asynchronous completion of the operation. The driver exposes lots of I/O operations, but having the most used ones (Find, FindOne, Insert...) implemented first that way would go a long way. |
| Comments |
| Comment by Craig Wilson [ 09/Feb/15 ] | ||||||||||||||||
|
Yaron, Yes, this ticket will be taken care of in 2.0.0. Currently, it's in beta2 form on nuget or on github. We'd love for you to use it and provide some feedback. Craig | ||||||||||||||||
| Comment by Yaron Levi [ 08/Feb/15 ] | ||||||||||||||||
|
Are there any updates regarding the release date of AWAIT/ASYNC support for the C# driver ? | ||||||||||||||||
| Comment by Craig Wilson [ 03/Sep/14 ] | ||||||||||||||||
|
We are closing this as it is slightly redundant. It fits in with a number of other tickets. This is absolutely a required part of our 2.0 release and we've built in async from the low level core and are building it into a new higher level API. It uses Tasks so that async await is possible. Feel free to keep commenting here if you'd like. | ||||||||||||||||
| Comment by Craig Wilson [ 26/Aug/14 ] | ||||||||||||||||
|
Yes, we have discussed this and will be adding ConfigureAwait everywhere (I think) internally as well. I'll open a ticket to ensure we don't forget. Thanks Ben. | ||||||||||||||||
| Comment by André Bires Fonseca [ 26/Aug/14 ] | ||||||||||||||||
|
Yes, its essential to avoid deadlocks when using it with WPF, ASP.Net and | ||||||||||||||||
| Comment by Fabien Brooke [ 26/Aug/14 ] | ||||||||||||||||
|
That makes more sense when in a UI application with a single UI thread and you have more work that doesn't require the SynchronizationContext. | ||||||||||||||||
| Comment by Ben Brockway [ 26/Aug/14 ] | ||||||||||||||||
|
It is good to see some progress is happening on this in GitHub. I have one concern/suggestion; When doing awaits, within a library, I think we should be using ConfigureAwait(false). This is an efficiency optimisation that is not yet widely known. A few quick links; Do you agree? | ||||||||||||||||
| Comment by Daniel Sinclair [ 22/Aug/14 ] | ||||||||||||||||
|
I hope there will be a "Migrating from 1.9 to 2.0" article. I already ran – @danieljsinclair | ||||||||||||||||
| Comment by Seif Attar [ 22/Aug/14 ] | ||||||||||||||||
|
Judging by the fact that this ticket is now in a sprint, and the dependencies resolved, I guess it won't be long before this is implemented. Looking forward to testing it! | ||||||||||||||||
| Comment by Daniel Sinclair [ 22/Aug/14 ] | ||||||||||||||||
|
That's awesome - and that's been available for how many hours exactly? :-P On 22 August 2014 02:46, André Bires Fonseca (JIRA) <jira@mongodb.org> – @danieljsinclair | ||||||||||||||||
| Comment by André Bires Fonseca [ 22/Aug/14 ] | ||||||||||||||||
|
Of if you are in Azure, you now can use the new DocumentDB database: | ||||||||||||||||
| Comment by Fabien Brooke [ 22/Aug/14 ] | ||||||||||||||||
|
Yes I use node.js for certain other things but this is a web api that I want to use C# for. Cassandra looks okay except that I need strong consistency. | ||||||||||||||||
| Comment by André Bires Fonseca [ 22/Aug/14 ] | ||||||||||||||||
|
Actually I'm not working with this code anymore. But it was working last time I used it, with some instabilities sometimes (the execution was hanging; I believe is something related to the connection pool that the driver implements). I was not familiar with the codebase and with the concepts of the protocol but I was able to make this almost-working async version of the driver in three days (including async LINQ). Maybe someone with more experience and time could improve it and release at least an alpha async version of the driver. Or depending of your level of desperation, you can move to Cassandra that have a very nice full-async C# driver: https://github.com/datastax/csharp-driver/ | ||||||||||||||||
| Comment by Mike McGranahan [ 21/Aug/14 ] | ||||||||||||||||
|
^ That solution does not use IOCP. It just moves the load from the threadpool to a tiny threadpool. It'll start blocking as soon as it hits 8 concurrent commands. See http://blogs.msdn.com/b/pfxteam/archive/2012/03/24/10287244.aspx . Andre Fonseca mentioned his in-progress work, which does use IOCP (e.g. https://github.com/andrebires/mongo-csharp-driver/blob/master/MongoDB.Bson/IO/BsonBuffer.cs#L713), in a comment above. | ||||||||||||||||
| Comment by Andrew Meggs [X] [ 21/Aug/14 ] | ||||||||||||||||
|
For what it's worth, if anybody is absolutely desperate, here's a very simple set of async wrappers that we use around the MongoDB C# API: These are just some simple static helper methods that queue a query to a separate thread pool and return a task that completes when your query does. They're obviously a very crude hack, and they don't handle very large result (because they gather the entire result and thencollapse it into a List<>), and they're only tested for 1.8 (not the current 1.9), and they don't support RequestStart() or anything but the most common entry points we use. But despite all that, they're working well enough for us today, and they've dramatically improved throughput on our server. To use them, just include the file in your project, and then you can do: List<MyType> result = await someCollection.FindAsAsync<MyType>( someQuery ); Be sure to call MongoAsyncHelpers.Shutdown() on exit. Hopefully this tiny contribution will help some of the people here until there's a supported and official solution. | ||||||||||||||||
| Comment by Khurram [ 21/Aug/14 ] | ||||||||||||||||
|
Hi Fabien, Don't want to troll here but I literally waited 1 year for this feature and then moved my app to NodeJS. MongoDB is really cool for certain tasks and C# driver is right now the only driver which doesn't support fully async non-blocking operations. Even scala (which is a comparatively new language) has this feature. | ||||||||||||||||
| Comment by Fabien Brooke [ 21/Aug/14 ] | ||||||||||||||||
|
Do you have a rough approximation of when 2.0 is to be released? Just wondering how much work to put in an app I've started for supporting things not included in the current version. | ||||||||||||||||
| Comment by Robert Stam [ 16/Jul/14 ] | ||||||||||||||||
|
Development has started on this feature, but the work is tied to some other tickets: 1. RequestStart will not work in any async environment because RequestStart is based on thread affinity. There will be some other mechanism, the details of which are still under discussion, for the application to indicate that a series of related operations should be sent to the server over the same connection. | ||||||||||||||||
| Comment by Eyal Post [ 16/Jul/14 ] | ||||||||||||||||
|
So I'm assuming development hasn't started on this yet, right? | ||||||||||||||||
| Comment by Robert Stam [ 11/Jul/14 ] | ||||||||||||||||
|
Sorry about the confusion with version numbers. The next version of the driver is 2.0, and will include async support. For a short while we were going to call the next major version 3.0 (long story), but currently the next major version is 2.0. The approach we are taking for 2.0 to support async and other improvements to the API is: 1. Create a new Core library (see We plan for the new Core library to be 100% async, and to implement sync versions of the high level APIs by simply blocking for the async tasks to complete. Because the granularity of the async tasks will be relatively coarse, we don't think this will cause significant overhead. This will result in less duplicate code. We do not plan to add async support to the legacy API, only to the new high level API. For the new high level API the plan is to provide two versions of the high level API: a sync version and an async version (rather than one high level API with both sync and async versions of each method). We think this has two major benefits: 1. You can't accidentally call sync versions of methods when writing async code (async code should be 100% async) | ||||||||||||||||
| Comment by Sergei Almazov [ 11/Jul/14 ] | ||||||||||||||||
|
Craig, I've started working on implementation of this feature (https://github.com/almazik/mongo-csharp-driver/tree/feature/CSHARP-138-AsyncAPI). Can anyone from the team review the changes to ensure that my approach corresponds to your vision? I'm extending existing classes/interfaces with corresponding async implementation, similarly to the way .NET libraries were extended with XxxAsync methods. It causes some level of code duplication, so I'm also refactoring common code where it seems necessary. | ||||||||||||||||
| Comment by Seif Attar [ 11/Jul/14 ] | ||||||||||||||||
|
Just to confirm that it is infact the 2.0 driver not the 3.0 driver? This ticket says 2.0 but Craig's last comment says 3.0. Looking forward to this happening. | ||||||||||||||||
| Comment by Craig Wilson [ 09/Apr/14 ] | ||||||||||||||||
|
Driver. Should be this year, yes. | ||||||||||||||||
| Comment by Stig Nielsson [ 09/Apr/14 ] | ||||||||||||||||
|
ok thanks. Is that 3.0 of the server or 3.0 of the c# driver? /Stig | ||||||||||||||||
| Comment by Craig Wilson [ 09/Apr/14 ] | ||||||||||||||||
|
It's scheduled for our next major version (3.0). | ||||||||||||||||
| Comment by Stig Nielsson [ 09/Apr/14 ] | ||||||||||||||||
|
Hi, I just saw that v. 1.9 of the driver was released on the 3rd of April but apparently without async support? https://github.com/mongodb/mongo-csharp-driver/blob/master/Release%20Notes/Release%20Notes%20v1.9.md Can we get an update about when async is expected to be supported ? /Stig | ||||||||||||||||
| Comment by André Bires Fonseca [ 18/Mar/14 ] | ||||||||||||||||
|
Since my company is awaiting for this feature and I thought that should be a good way to learn better how the protocol works, I've started today to try to make a async version of the driver. I began from the MongoConnection class, changing the Read and Write Networkstream methods to the async version and propagating the changes by the code. Besides that, I've made some changes in the way the connection locks (using SemaphoreSlim instead of a lock), but the behavior is still a lot buggy. For LINQ support, I've created async interfaces (IEnumeratorAsync and IEnumerableAsync) and implemented the FirstOrDefaultAsync method for this interface (is the only one true async LINQ method). I'll try to implement the others soon. PS: The tests are not working yet. EDIT: I've included the async LINQ methods and implemented the basic support for most of operations (ToListAsync, FirstOrDefaultAsync, FirstAsync, ToDictionaryAsync, and so). I made an adaption from the EF6.1 async implementation to make this possible. | ||||||||||||||||
| Comment by Dmitriy@ITAdapter [ 24/Jan/14 ] | ||||||||||||||||
|
People, the absence of ASYNC support in MongoDB .NET driver really kills the deal for us. Our case: | ||||||||||||||||
| Comment by Attila Hajdrik [ 11/Nov/13 ] | ||||||||||||||||
|
Hi Craig! Thanks for the update Keep up the good work! | ||||||||||||||||
| Comment by Craig Wilson [ 09/Nov/13 ] | ||||||||||||||||
|
Hi Attila, We don't have an ETA yet, but it will likely be Q1 of 2014. In addition, async will only be supported for .NET 4.5. | ||||||||||||||||
| Comment by Attila Hajdrik [ 09/Nov/13 ] | ||||||||||||||||
|
Any update on this? October passed, November is almost in the middle and as I've checked out the v2.0 driver branch saw no sign of any "async" or "await" in the code. Thanks, | ||||||||||||||||
| Comment by Bar Arnon [ 24/Oct/13 ] | ||||||||||||||||
|
I would like to join in... public static async Task<int> SumAsync<TSource>(this IQueryable<TSource> source); Thanks, | ||||||||||||||||
| Comment by Hatch [ 21/Sep/13 ] | ||||||||||||||||
|
Agree with above. This is critical for adoption of MongoDB by my team. This is important for any high-performance database, but especially for MongoDB given that so many operations involve multiple queries to the database that might have traditionally been performed in a single request. | ||||||||||||||||
| Comment by Clifford Hammerschmidt [ 05/Sep/13 ] | ||||||||||||||||
|
My team wants the task based approach, as we are moving towards async/await for everything and building on top of HttpListerner GetContextAsync. The sooner we can get this, the better. | ||||||||||||||||
| Comment by Khurram [ 23/Jul/13 ] | ||||||||||||||||
|
Hi Craig, I've MongoDB behind a web app which has about 300 million hits/month. Each visit generate 6-7 mongodb read and writes. The app is on Linux, means we don't have IIS. NGINX and Apache are not the option with Mono for me. To avoid all the concurrency problems I modeled the app in a single threaded way, means app runs in a single thread. (All new web frameworks .NET WebApi, Nancy, ServiceStack provides async + in-app hosting facility, where you don't need IIS do deploy the app) With mongodb I can't scale that app to more than 20-30 requests/second. I moved the app to NodeJS and its amazingly fast. Because of all the non-blocking IO. Just because C# doesn't have Async driver I can't scale my app beyond 20-30 requets/second with mono. I had to move to NodeJS. I can easily scale upto couple of thousands requests/second on NodeJS. The big obstacle with C# is the blocking calls to mongo. The thread gets freezed for 30-40 ms for each round-trip to mongo and can't do anything. I guess its a very common use case for todays' web apps. Asp.NET signalR, websockets and all the katana stuff, non-blocking IO isn't only a luxury but a very fundamental requirement. | ||||||||||||||||
| Comment by Craig Wilson [ 11/Jul/13 ] | ||||||||||||||||
|
We are currently working on it. October/November is likely the earliest for 2.0 as we are rewriting the portions of the driver that need to be async friendly. Would you mind elaborating on what you expect async is going to provide you and why you can't use it today with blocking calls? | ||||||||||||||||
| Comment by Khurram [ 11/Jul/13 ] | ||||||||||||||||
|
I've been waiting for async driver for long because its a show stopper for me to use blocking calls in production. I'm excited that finally its been taking care in v2.0. Any ideas when we can expect a first alpha release ? | ||||||||||||||||
| Comment by Cameron Taggart [ 11/Apr/13 ] | ||||||||||||||||
|
Just supporting the new Task based async makes sense. Really looking forward to trying it out. | ||||||||||||||||
| Comment by Flavien [ 21/Mar/13 ] | ||||||||||||||||
|
Wow, that's great news, thanks! | ||||||||||||||||
| Comment by Craig Wilson [ 14/Mar/13 ] | ||||||||||||||||
|
Yes, this is going to be one of the most important additions to the 2.0 driver. We have not yet decided on which version(s) to support. We are leaning towards just support the Task based version as we will be upgrading to .NET 4 with the 2.0 release anyways. | ||||||||||||||||
| Comment by Flavien [ 14/Mar/13 ] | ||||||||||||||||
|
Is that going to be addressed in 2.0? Just as pointed out above, you don't have to target .NET 4.0 to address this, just expose BeginXXX/EndXXX methods. It's easy to then turns them into a Task usable with await if someone needs to, using Task.Factory.FromAsync. | ||||||||||||||||
| Comment by Nicholas Bellerophon [ 01/Feb/13 ] | ||||||||||||||||
|
Having async in the C# would make an enormous difference for us. Please add it! As a mono user, I'd definitely prefer use of the backwards-compatible pattern. | ||||||||||||||||
| Comment by Alan [ 16/Jan/13 ] | ||||||||||||||||
|
I am also in dire need of this feature. Would love to see it soon... Almost every other language has an async library except for .NET. | ||||||||||||||||
| Comment by Terence Craig [ 02/Dec/12 ] | ||||||||||||||||
|
This functionality would be very useful for us as well. Does the availability of the Async Targeting Pack http://www.microsoft.com/en-us/download/details.aspx?id=29576 which adds support for the Async Keyword on .NET 4.0 change the scheduling concerns mentioned in Robert's earlier comment? Or does the fact that the targeting pack requires Visual Studio 11 still make scheduling this problematic? | ||||||||||||||||
| Comment by Mike McGranahan [ 14/Sep/12 ] | ||||||||||||||||
|
(Er, the event argument in that example is just an extension of System.ComponentModel.AsyncCompletedEventArgs that adds an Argument property of type Tuple<object, int>. Item1 holds userState, possibly needed to determine if the handler delegate is appropriate for the invocation, and Item2 the result computed from the given input.) | ||||||||||||||||
| Comment by Mike McGranahan [ 14/Sep/12 ] | ||||||||||||||||
|
Great news! If it's just a matter of deciding the approach, consider the following. We've got three established patterns for asynchronous APIs in .NET: event-based asynchronous pattern (EAP), asynchronous programming model (APM), and Task-based asyncronous pattern (TAP):
The nice thing about the TPL is that you can easily wrap the APM pattern with TaskFactory.FromAsync. It's so trivial you could leave that to the application, and simply deliver an APM implementation. On the other hand, using TaskCompletionSource to wrap EAP is straightforward as well. E.g. (doesn't demonstrate progress):
In the past, I've actually implemented all three simultaneously, where both the APM and TAP implementations are based on the EAP implementation. This approach could be used without the TAP implementation in order to remain compatible with .NET 2.0. Optional: To prevent both EAP and APM from cluttering IntelliSense, you could hide one or the other. Although this pre-.NET 4.0 article <http://msdn.microsoft.com/en-us/library/ms228966.aspx> recommends hiding the APM implementation, you might want to hide EAP so it's easier to wrap with TaskFactory.FromAsync. | ||||||||||||||||
| Comment by Robert Stam [ 14/Sep/12 ] | ||||||||||||||||
|
I believe the only reason it is marked as minor is because it was marked as minor by the original creator of the JIRA issue and no one has touched it since. I'm fine with changing this to major and will do so. The scheduling of this depends a lot on whether we feel that async support should use the latest recommended async patterns from .NET 4.5 and C# 5. It seems a shame to implement a version of async support that uses the obsolete .NET 3.5 async patterns when those patterns have already been replaced with better ones. And the problem with basing our async implementation on .NET 4.5 and C# 5 is that raising the minimum .NET requirement for using the driver all the way to .NET 4.5 might be too cutting edge for some of our users (and would almost certainly cause problems for our Mono users). Therefore the scheduling is uncertain, even though the merits of supporting async are not in question. | ||||||||||||||||
| Comment by mickdelaney [ 14/Sep/12 ] | ||||||||||||||||
|
This is a big missing piece for mongo with .net can we at least here a solid reason why this is still perceived as 'minor' ? | ||||||||||||||||
| Comment by Mike McGranahan [ 05/Sep/12 ] | ||||||||||||||||
|
(Cross-posted to To keep this discussion alive, I'd like to point to this comparison of async/IOCP-based code vs blocking code: http://stackoverflow.com/a/6230846/29805 . (Just substitute a MongoCollection.Find call for Thread.Sleep.) Without IOCP, ASP.NET can only handle 9 simultaneous requests at once this benchmark. With IOCP, ASP.NET can start asynchronously processing all requests almost simultaneously, leading to a 97% decrease in overall execution time! Leveraging IOCP in the C# driver is absolutely critical for high-performance .NET applications. Adding this would be a quick win for performance. | ||||||||||||||||
| Comment by Grégoire Seux [ 23/Aug/12 ] | ||||||||||||||||
|
It would very useful for me either. | ||||||||||||||||
| Comment by Matt Dotson [ 17/Jun/12 ] | ||||||||||||||||
|
I agree that this should be a much higher priority. For me this is pretty much a deal breaker for mongo in production until it's available. I like mongo a lot, but I feel like I'd be giving up too much with ASP.NET calling a synchronous api. That's just a recipe for not scaling. I haven't looked how the driver is implemented but if it's using deferred execution, then db.Find(...).AsAsync() would be a nice way to support the Async calls on all the methods. By the way, this is listed as a "minor" issue with an easy workaround? What's the easy workaround to get non-blocking io with the mongo driver? This should be classified as major. | ||||||||||||||||
| Comment by s n [ 18/May/12 ] | ||||||||||||||||
|
TPL is not required for making an async API, so support for async need not wait for you to upgrade to C# 4.0. I too would very very much like to see async support soon in the C# driver. | ||||||||||||||||
| Comment by Craig Wilson [ 18/May/12 ] | ||||||||||||||||
|
As we don't support native .NET 4.0, we don't have the bits to work with the TPL. Since we are planning to add formal support for .NET 4.0 in version 2.0 of the driver, this would be an area we would look into and see if there is any benefit to adding async support to the driver. | ||||||||||||||||
| Comment by Mike McGranahan [ 18/May/12 ] | ||||||||||||||||
|
Haven't dug too deep, but since MongoCursor exposes a fluent interface, one approach to providing asynchronous execution would be for MongoCursor<T> to provide a method StartToList which returns something like Task<IList<T>>. (The implementation would start a Task to eagerly do the processing from MongoCursorEnumerator, and pass the parameters to a new MongoConnection method StartReceiveMessage. This returns a Task<MongoReplyMessage> and would ultimately delegate to the new BsonBuffer.StartLoadFrom, which could use TaskFactory.FromAsync to wrap Stream.Begin/EndRead.) Such a critical performance feature should be more highly prioritized, and at least should be scheduled. Once C# 5.0 is released, I imagine .NET users will be much more vocal about their desire for it. | ||||||||||||||||
| Comment by Michael Catanzariti [ 15/Mar/12 ] | ||||||||||||||||
|
The main problem is that It's rather the first invocation to MongoCursorEnumerator.MoveNext (when a MongoCursor is enumerated in a foreach or a ToList) that actually connects to the database and sends a OP_QUERY message. Moreover subsequent calls to MongoCursorEnumerator.MoveNext could lead to send a OP_GETMORE command to the server if the first OP_QUERY was not enough to fetch the whole document batch from the server. It means that | ||||||||||||||||
| Comment by manish patel [ 04/Aug/11 ] | ||||||||||||||||
|
Agree with Flavien, once async is done, using it in sync fashion do not need any work at all. | ||||||||||||||||
| Comment by Flavien [ 26/Jul/11 ] | ||||||||||||||||
|
Aristarkh: I agree with you, wrapping synchronous operations in thread pool thread doesn't fit the bill, what we need is that at the lowest level, socket operations use the asynchronous versions (BeginReadByte/EndReadByte instead of ReadByte). That would ensure true asynchrony. I don't agree that "it would require duplicating a fair amount of existing I/O code to cover the asynchronous case". Asynchronous APIs cannot be implemented using synchonous APIs, however implementing synchronous APIs using asynchronous APIs is trivial. You don't need to duplicate code, having the asynchronous version only is enough: reimplemeting the synchronous version using the asynchronous one is just a few lines of code. And synchronous IO is evil anyway, and in an ideal world should not even be exposed. | ||||||||||||||||
| Comment by Aristarkh Zagorodnikov [ 28/May/11 ] | ||||||||||||||||
|
I would like to note that creating asynchronous code by delegating fragments of work to worker thread pool would likely only harm the performance, unless you mostly perform lengthy operations. I believe that using MongoDB from an ASP.NET and/or WCF server is the common pattern, and in this case, using thread pool threads for database calls would only increase load on garbage collector due to need to set up and tear down additional state. Unless you want split-parallel execution to decrease latency, server applications should not use CPU asynchronicity (we learned it the hard way here). Even if you're reducing latency, the split-parallel execution might actually make latency worse when server approaches its capacity. Of course, if asycnhronicity is performed at the I/O level (socket IOCP), then it would have its benefits. But, implementing I/O-level asynchronicity ain't that easy, because it would require duplicating a fair amount of existing I/O code to cover the asynchronous case. | ||||||||||||||||
| Comment by Virgile Bello [ 25/Apr/11 ] | ||||||||||||||||
|
As I ran into the issue, here is an auto-generated wrapper around MongoCollection and MongoCollection<T>. If you want source of the template script, I can provide it as well. |