From 0ef9ec292b577c5ecd299aed99e085cb1dce09de Mon Sep 17 00:00:00 2001 From: Jon Hanna Date: Sun, 15 Jan 2017 01:34:37 +0000 Subject: [PATCH] Don't explicitly check for Failed or Cancelled Statuses (#1179) Between discussion at #1137 and a few rounds of revision at #1159 we arrived at an optimisation where tasks that are both heavily hit and very likely to return in a completed state are checked for a status of either RanToCompletion, Canceled or Faulted and a path is taken where no await is needed for any of those. The Canceled and Faulted tasks are returned immediately, allowing that state to be passed to the caller. However, these are exceptional cases, and if we just continued the subsequent await would raise the appropriate exception. Checking for all three cases instead of just RanToCompletion is optimising for those execptional conditions at cost (in the form of a larger comparison segment of code) to the more common cases of the task either being completed or still running. Simplify this back to a check just for RanToCompletion. --- Src/Newtonsoft.Json/JsonTextReader.Async.cs | 10 +-- Src/Newtonsoft.Json/JsonTextWriter.Async.cs | 84 +++++-------------- Src/Newtonsoft.Json/Linq/JProperty.Async.cs | 8 +- .../Utilities/JavaScriptUtils.cs | 20 +---- 4 files changed, 29 insertions(+), 93 deletions(-) diff --git a/Src/Newtonsoft.Json/JsonTextReader.Async.cs b/Src/Newtonsoft.Json/JsonTextReader.Async.cs index 8bae6915..7ad7659b 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.Async.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.Async.cs @@ -495,14 +495,10 @@ namespace Newtonsoft.Json _charPos++; Task task = EnsureCharsAsync(1, append, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.RanToCompletion: - SetNewLine(task.Result); - return AsyncUtils.CompletedTask; - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; + SetNewLine(task.Result); + return AsyncUtils.CompletedTask; } return ProcessCarriageReturnAsync(task); diff --git a/Src/Newtonsoft.Json/JsonTextWriter.Async.cs b/Src/Newtonsoft.Json/JsonTextWriter.Async.cs index b2f746f6..b7414f46 100644 --- a/Src/Newtonsoft.Json/JsonTextWriter.Async.cs +++ b/Src/Newtonsoft.Json/JsonTextWriter.Async.cs @@ -186,13 +186,9 @@ namespace Newtonsoft.Json private Task WriteValueInternalAsync(JsonToken token, string value, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(token, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - return _writer.WriteAsync(value, cancellationToken); + return _writer.WriteAsync(value, cancellationToken); } return WriteValueInternalAsync(task, value, cancellationToken); @@ -270,13 +266,9 @@ namespace Newtonsoft.Json private Task WriteIntegerValueAsync(ulong uvalue, bool negative, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.Integer, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - return WriteDigitsAsync(uvalue, negative, cancellationToken); + return WriteDigitsAsync(uvalue, negative, cancellationToken); } return WriteIntegerValueAsync(task, uvalue, negative, cancellationToken); @@ -325,27 +317,15 @@ namespace Newtonsoft.Json internal Task DoWritePropertyNameAsync(string name, CancellationToken cancellationToken) { Task task = InternalWritePropertyNameAsync(name, cancellationToken); - switch (task.Status) + if (task.Status != TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - // Completed synchronously (or very fast!), continue within this rather - // that the default branch which uses async - break; - default: - return DoWritePropertyNameAsync(task, name, cancellationToken); + return DoWritePropertyNameAsync(task, name, cancellationToken); } task = WriteEscapedStringAsync(name, _quoteName, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - return _writer.WriteAsync(':', cancellationToken); + return _writer.WriteAsync(':', cancellationToken); } return JavaScriptUtils.WriteCharAsync(task, _writer, ':', cancellationToken); @@ -415,13 +395,9 @@ namespace Newtonsoft.Json internal Task DoWriteStartArrayAsync(CancellationToken cancellationToken) { Task task = InternalWriteStartAsync(JsonToken.StartArray, JsonContainerType.Array, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - return _writer.WriteAsync('[', cancellationToken); + return _writer.WriteAsync('[', cancellationToken); } return DoWriteStartArrayAsync(task, cancellationToken); @@ -449,13 +425,9 @@ namespace Newtonsoft.Json internal Task DoWriteStartObjectAsync(CancellationToken cancellationToken) { Task task = InternalWriteStartAsync(JsonToken.StartObject, JsonContainerType.Object, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - return _writer.WriteAsync('{', cancellationToken); + return _writer.WriteAsync('{', cancellationToken); } return DoWriteStartObjectAsync(task, cancellationToken); @@ -505,13 +477,9 @@ namespace Newtonsoft.Json internal Task DoWriteUndefinedAsync(CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.Undefined, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - return _writer.WriteAsync(JsonConvert.Undefined, cancellationToken); + return _writer.WriteAsync(JsonConvert.Undefined, cancellationToken); } return DoWriteUndefinedAsync(task, cancellationToken); @@ -1086,13 +1054,9 @@ namespace Newtonsoft.Json internal Task DoWriteValueAsync(string value, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - return value == null ? _writer.WriteAsync(JsonConvert.Null, cancellationToken) : WriteEscapedStringAsync(value, true, cancellationToken); + return value == null ? _writer.WriteAsync(JsonConvert.Null, cancellationToken) : WriteEscapedStringAsync(value, true, cancellationToken); } return DoWriteValueAsync(task, value, cancellationToken); @@ -1225,13 +1189,9 @@ namespace Newtonsoft.Json internal Task WriteValueNotNullAsync(Uri value, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - return WriteEscapedStringAsync(value.OriginalString, true, cancellationToken); + return WriteEscapedStringAsync(value.OriginalString, true, cancellationToken); } return WriteValueNotNullAsync(task, value, cancellationToken); @@ -1350,13 +1310,9 @@ namespace Newtonsoft.Json { UpdateScopeWithFinishedValue(); Task task = AutoCompleteAsync(JsonToken.Undefined, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - return WriteRawAsync(json, cancellationToken); + return WriteRawAsync(json, cancellationToken); } return DoWriteRawValueAsync(task, json, cancellationToken); diff --git a/Src/Newtonsoft.Json/Linq/JProperty.Async.cs b/Src/Newtonsoft.Json/Linq/JProperty.Async.cs index 77ce7341..083e228d 100644 --- a/Src/Newtonsoft.Json/Linq/JProperty.Async.cs +++ b/Src/Newtonsoft.Json/Linq/JProperty.Async.cs @@ -44,13 +44,9 @@ namespace Newtonsoft.Json.Linq public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters) { Task task = writer.WritePropertyNameAsync(_name, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - return WriteValueAsync(writer, cancellationToken, converters); + return WriteValueAsync(writer, cancellationToken, converters); } return WriteToAsync(task, writer, cancellationToken, converters); diff --git a/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs index ad5e2fd0..32cf9d84 100644 --- a/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs @@ -381,29 +381,17 @@ namespace Newtonsoft.Json.Utilities bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, JsonTextWriter client, char[] writeBuffer, CancellationToken cancellationToken) { Task task = writer.WriteAsync(delimiter, cancellationToken); - switch (task.Status) + if (task.Status != TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - // Completed synchronously (or very fast!), continue within this rather - // that the default branch which uses async - break; - default: - return WriteEscapedJavaScriptStringWithDelimitersAsync(task, writer, s, delimiter, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken); + return WriteEscapedJavaScriptStringWithDelimitersAsync(task, writer, s, delimiter, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken); } if (!string.IsNullOrEmpty(s)) { task = WriteEscapedJavaScriptStringWithoutDelimitersAsync(writer, s, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken); - switch (task.Status) + if (task.Status == TaskStatus.RanToCompletion) { - case TaskStatus.Canceled: - case TaskStatus.Faulted: - return task; - case TaskStatus.RanToCompletion: - return writer.WriteAsync(delimiter, cancellationToken); + return writer.WriteAsync(delimiter, cancellationToken); } }