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++;
Task<bool> 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);
+20 -64
View File
@@ -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);
+2 -6
View File
@@ -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);
@@ -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);
}
}