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.
This commit is contained in:
Jon Hanna
2017-01-15 14:34:37 +13:00
committed by James Newton-King
parent 3b583b886f
commit 0ef9ec292b
4 changed files with 29 additions and 93 deletions
+3 -7
View File
@@ -495,14 +495,10 @@ namespace Newtonsoft.Json
_charPos++; _charPos++;
Task<bool> task = EnsureCharsAsync(1, append, cancellationToken); Task<bool> task = EnsureCharsAsync(1, append, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.RanToCompletion: SetNewLine(task.Result);
SetNewLine(task.Result); return AsyncUtils.CompletedTask;
return AsyncUtils.CompletedTask;
case TaskStatus.Canceled:
case TaskStatus.Faulted:
return task;
} }
return ProcessCarriageReturnAsync(task); return ProcessCarriageReturnAsync(task);
+20 -64
View File
@@ -186,13 +186,9 @@ namespace Newtonsoft.Json
private Task WriteValueInternalAsync(JsonToken token, string value, CancellationToken cancellationToken) private Task WriteValueInternalAsync(JsonToken token, string value, CancellationToken cancellationToken)
{ {
Task task = InternalWriteValueAsync(token, cancellationToken); Task task = InternalWriteValueAsync(token, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return _writer.WriteAsync(value, cancellationToken);
case TaskStatus.Faulted:
return task;
case TaskStatus.RanToCompletion:
return _writer.WriteAsync(value, cancellationToken);
} }
return WriteValueInternalAsync(task, value, cancellationToken); return WriteValueInternalAsync(task, value, cancellationToken);
@@ -270,13 +266,9 @@ namespace Newtonsoft.Json
private Task WriteIntegerValueAsync(ulong uvalue, bool negative, CancellationToken cancellationToken) private Task WriteIntegerValueAsync(ulong uvalue, bool negative, CancellationToken cancellationToken)
{ {
Task task = InternalWriteValueAsync(JsonToken.Integer, cancellationToken); Task task = InternalWriteValueAsync(JsonToken.Integer, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return WriteDigitsAsync(uvalue, negative, cancellationToken);
case TaskStatus.Faulted:
return task;
case TaskStatus.RanToCompletion:
return WriteDigitsAsync(uvalue, negative, cancellationToken);
} }
return WriteIntegerValueAsync(task, uvalue, negative, cancellationToken); return WriteIntegerValueAsync(task, uvalue, negative, cancellationToken);
@@ -325,27 +317,15 @@ namespace Newtonsoft.Json
internal Task DoWritePropertyNameAsync(string name, CancellationToken cancellationToken) internal Task DoWritePropertyNameAsync(string name, CancellationToken cancellationToken)
{ {
Task task = InternalWritePropertyNameAsync(name, cancellationToken); Task task = InternalWritePropertyNameAsync(name, cancellationToken);
switch (task.Status) if (task.Status != TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return DoWritePropertyNameAsync(task, name, cancellationToken);
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);
} }
task = WriteEscapedStringAsync(name, _quoteName, cancellationToken); task = WriteEscapedStringAsync(name, _quoteName, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return _writer.WriteAsync(':', cancellationToken);
case TaskStatus.Faulted:
return task;
case TaskStatus.RanToCompletion:
return _writer.WriteAsync(':', cancellationToken);
} }
return JavaScriptUtils.WriteCharAsync(task, _writer, ':', cancellationToken); return JavaScriptUtils.WriteCharAsync(task, _writer, ':', cancellationToken);
@@ -415,13 +395,9 @@ namespace Newtonsoft.Json
internal Task DoWriteStartArrayAsync(CancellationToken cancellationToken) internal Task DoWriteStartArrayAsync(CancellationToken cancellationToken)
{ {
Task task = InternalWriteStartAsync(JsonToken.StartArray, JsonContainerType.Array, cancellationToken); Task task = InternalWriteStartAsync(JsonToken.StartArray, JsonContainerType.Array, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return _writer.WriteAsync('[', cancellationToken);
case TaskStatus.Faulted:
return task;
case TaskStatus.RanToCompletion:
return _writer.WriteAsync('[', cancellationToken);
} }
return DoWriteStartArrayAsync(task, cancellationToken); return DoWriteStartArrayAsync(task, cancellationToken);
@@ -449,13 +425,9 @@ namespace Newtonsoft.Json
internal Task DoWriteStartObjectAsync(CancellationToken cancellationToken) internal Task DoWriteStartObjectAsync(CancellationToken cancellationToken)
{ {
Task task = InternalWriteStartAsync(JsonToken.StartObject, JsonContainerType.Object, cancellationToken); Task task = InternalWriteStartAsync(JsonToken.StartObject, JsonContainerType.Object, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return _writer.WriteAsync('{', cancellationToken);
case TaskStatus.Faulted:
return task;
case TaskStatus.RanToCompletion:
return _writer.WriteAsync('{', cancellationToken);
} }
return DoWriteStartObjectAsync(task, cancellationToken); return DoWriteStartObjectAsync(task, cancellationToken);
@@ -505,13 +477,9 @@ namespace Newtonsoft.Json
internal Task DoWriteUndefinedAsync(CancellationToken cancellationToken) internal Task DoWriteUndefinedAsync(CancellationToken cancellationToken)
{ {
Task task = InternalWriteValueAsync(JsonToken.Undefined, cancellationToken); Task task = InternalWriteValueAsync(JsonToken.Undefined, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return _writer.WriteAsync(JsonConvert.Undefined, cancellationToken);
case TaskStatus.Faulted:
return task;
case TaskStatus.RanToCompletion:
return _writer.WriteAsync(JsonConvert.Undefined, cancellationToken);
} }
return DoWriteUndefinedAsync(task, cancellationToken); return DoWriteUndefinedAsync(task, cancellationToken);
@@ -1086,13 +1054,9 @@ namespace Newtonsoft.Json
internal Task DoWriteValueAsync(string value, CancellationToken cancellationToken) internal Task DoWriteValueAsync(string value, CancellationToken cancellationToken)
{ {
Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken); Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return value == null ? _writer.WriteAsync(JsonConvert.Null, cancellationToken) : WriteEscapedStringAsync(value, true, cancellationToken);
case TaskStatus.Faulted:
return task;
case TaskStatus.RanToCompletion:
return value == null ? _writer.WriteAsync(JsonConvert.Null, cancellationToken) : WriteEscapedStringAsync(value, true, cancellationToken);
} }
return DoWriteValueAsync(task, value, cancellationToken); return DoWriteValueAsync(task, value, cancellationToken);
@@ -1225,13 +1189,9 @@ namespace Newtonsoft.Json
internal Task WriteValueNotNullAsync(Uri value, CancellationToken cancellationToken) internal Task WriteValueNotNullAsync(Uri value, CancellationToken cancellationToken)
{ {
Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken); Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return WriteEscapedStringAsync(value.OriginalString, true, cancellationToken);
case TaskStatus.Faulted:
return task;
case TaskStatus.RanToCompletion:
return WriteEscapedStringAsync(value.OriginalString, true, cancellationToken);
} }
return WriteValueNotNullAsync(task, value, cancellationToken); return WriteValueNotNullAsync(task, value, cancellationToken);
@@ -1350,13 +1310,9 @@ namespace Newtonsoft.Json
{ {
UpdateScopeWithFinishedValue(); UpdateScopeWithFinishedValue();
Task task = AutoCompleteAsync(JsonToken.Undefined, cancellationToken); Task task = AutoCompleteAsync(JsonToken.Undefined, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return WriteRawAsync(json, cancellationToken);
case TaskStatus.Faulted:
return task;
case TaskStatus.RanToCompletion:
return WriteRawAsync(json, cancellationToken);
} }
return DoWriteRawValueAsync(task, json, cancellationToken); return DoWriteRawValueAsync(task, json, cancellationToken);
+2 -6
View File
@@ -44,13 +44,9 @@ namespace Newtonsoft.Json.Linq
public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters) public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters)
{ {
Task task = writer.WritePropertyNameAsync(_name, cancellationToken); Task task = writer.WritePropertyNameAsync(_name, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return WriteValueAsync(writer, cancellationToken, converters);
case TaskStatus.Faulted:
return task;
case TaskStatus.RanToCompletion:
return WriteValueAsync(writer, cancellationToken, converters);
} }
return WriteToAsync(task, writer, cancellationToken, converters); return WriteToAsync(task, writer, cancellationToken, converters);
@@ -381,29 +381,17 @@ namespace Newtonsoft.Json.Utilities
bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, JsonTextWriter client, char[] writeBuffer, CancellationToken cancellationToken) bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, JsonTextWriter client, char[] writeBuffer, CancellationToken cancellationToken)
{ {
Task task = writer.WriteAsync(delimiter, cancellationToken); Task task = writer.WriteAsync(delimiter, cancellationToken);
switch (task.Status) if (task.Status != TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return WriteEscapedJavaScriptStringWithDelimitersAsync(task, writer, s, delimiter, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken);
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);
} }
if (!string.IsNullOrEmpty(s)) if (!string.IsNullOrEmpty(s))
{ {
task = WriteEscapedJavaScriptStringWithoutDelimitersAsync(writer, s, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken); task = WriteEscapedJavaScriptStringWithoutDelimitersAsync(writer, s, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken);
switch (task.Status) if (task.Status == TaskStatus.RanToCompletion)
{ {
case TaskStatus.Canceled: return writer.WriteAsync(delimiter, cancellationToken);
case TaskStatus.Faulted:
return task;
case TaskStatus.RanToCompletion:
return writer.WriteAsync(delimiter, cancellationToken);
} }
} }