-
-
Notifications
You must be signed in to change notification settings - Fork 491
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
Adding async methods to serialization API #908
base: master
Are you sure you want to change the base?
Conversation
There are several questions that I ran into right away. First is that while adding the appropriate Second, following the original comments in pull request #457 before it was closed (and my own inspection of the code), it seems unavoidable that at least the Emitter will have to change. The changes in that class will revolve around the StateMachine method. That method handles the logic of serialization and writing the results (through the Write and WriteBreak methods). To make that work with the asynchronous API, I see two paths: refactoring or duplicating the code with a Third, and most tricky as far as I can tell, is the ValueSerializer class. From what it looks like, the SerializeValue method and Lastly, is it preferred to have the asynchronous methods return While I haven't added any tests of substance in the branch yet, I plan on finishing those once the bigger issues are taken care of. Of course I welcome any comments, concerns, questions, etc, including those that I haven't touched on. |
The commit I just made updates the |
One idea to help reduce the breaking change on the supporting interfaces like the value serializer. Create 2 interfaces. The first would be ivalueserializerbase and would have nothing in it. The old interface would inherit it. The new interface would also inherit it. The new interface would have the async methods. In the builders you change the method signatures and everywhere else to take the base interface. Where the current interface is called you would do a check. If the type is the old one, call the synchronous method, else call async. Hopefully that makes sense. It’s how I’ve done changes like this in the past and it worked well. |
I've been going around in circles with implementing this, primarily because there's no safe way to call async methods in synchronous methods without risking a deadlock (if there is and I've missed it, I would love to be wrong). As a consequence, it's not safe to allow the user to register, for example, an |
@@ -77,11 +78,21 @@ public T Deserialize<T>(TextReader input) | |||
return Deserialize<T>(new Parser(input)); | |||
} | |||
|
|||
public async Task<T> DeserializeAsync<T>(TextReader input) | |||
{ | |||
return await DeserializeAsync<T>(new Parser(input)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of return await
I would just return the task directly
@@ -402,6 +403,19 @@ public void Emit(ParsingEvent @event) | |||
|
|||
Assert.False(scalar.IsQuotedImplicit); | |||
} | |||
|
|||
public Task EmitAsync(ParsingEvent @event) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest to have a CancellationToken
parameter in all async mathods
I would prefer extending the existing interfaces and create abstract base classes, which just call the synchronous versions. These can then be used by library users to easily upgrade without being required to implement all async methods. The base classes should not be used inside the YamlDotNet library and may also be marked as obsolete to clearly state that this is not the suggested way, but only a workaround to postpone the required changes. |
Have you looked in to how system.text.json handles this? |
@zivillian Thank you for the input and the suggestions. I got partially finished with another commit that addresses some of that, but it's been a while since I've touched it, so it'll be a while before I can complete and push it. @EdwardCooke I looked into the source code of The main infrastructure issue is that the Deserializer is a direct data pipeline from the Stream, to the components (
|
This draft is to bring up the question of adding Async versions of the Serialize and Deserialize APIs, and all of the complexity that that will entail. This was brought up originally in issue #430. So far my branch only contains more or less what the closed pull request #457 had.
Before I go any further I want to make sure that I address a series of architectural questions and concerns (which I'll put in the following comment) that might block the implementation due to how deeply the code will have to be modified.