Skip to content

Commit 45dad1e

Browse files
lifenglLifeng Lu
andauthored
reduce overhead when running in no main thread mode (#1502)
* Do not track nested factory when there is no main thread Generally, post to context would not be used as SwitchToMainThread is no-op in this context. Even it is being called under certain corner cases, it would just queue the same work item to the thread pool multiple times, so better to prevent the allocation in the first place. * Do not turn on SynchronouslyBlockingMainThread flag on when the JTF is used in no main thread mode. Because IsOnMainThread is just to check the thread id, this can be turned on randomly when the code is running in the initial thread pool thread. It would turn on expensive dependency tracking graph, which is not what we expect to do. * stop creating main thread synchronization context when running in no main thread mode. --------- Co-authored-by: Lifeng Lu <[email protected]>
1 parent e700b50 commit 45dad1e

File tree

2 files changed

+18
-16
lines changed

2 files changed

+18
-16
lines changed

src/Microsoft.VisualStudio.Threading/JoinableTask.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using System.Linq;
99
using System.Reflection;
1010
using System.Runtime.CompilerServices;
11-
using System.Text;
1211
using System.Threading;
1312
using System.Threading.Tasks;
1413
using JoinRelease = Microsoft.VisualStudio.Threading.JoinableTaskCollection.JoinRelease;
@@ -147,7 +146,7 @@ internal JoinableTask(JoinableTaskFactory owner, bool synchronouslyBlocking, str
147146
this.state |= JoinableTaskFlags.StartedSynchronously | JoinableTaskFlags.CompletingSynchronously;
148147
}
149148

150-
if (owner.Context.IsOnMainThread)
149+
if (owner.Context.IsOnMainThread && !this.JoinableTaskContext.IsNoOpContext)
151150
{
152151
this.state |= JoinableTaskFlags.StartedOnMainThread;
153152
if (synchronouslyBlocking)
@@ -321,7 +320,7 @@ internal SynchronizationContext? ApplicableJobSyncContext
321320
{
322321
get
323322
{
324-
if (this.JoinableTaskContext.IsOnMainThread)
323+
if (this.JoinableTaskContext.IsOnMainThread && !this.JoinableTaskContext.IsNoOpContext)
325324
{
326325
if (this.mainThreadJobSyncContext is null)
327326
{
@@ -977,7 +976,7 @@ internal void CompleteOnCurrentThread()
977976
{
978977
bool onMainThread = false;
979978
JoinableTaskFlags additionalFlags = JoinableTaskFlags.CompletingSynchronously;
980-
if (this.JoinableTaskContext.IsOnMainThread)
979+
if (this.JoinableTaskContext.IsOnMainThread && !this.JoinableTaskContext.IsNoOpContext)
981980
{
982981
additionalFlags |= JoinableTaskFlags.SynchronouslyBlockingMainThread;
983982
onMainThread = true;

src/Microsoft.VisualStudio.Threading/JoinableTaskFactory.cs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public partial class JoinableTaskFactory
2828
/// </summary>
2929
private readonly JoinableTaskContext owner;
3030

31-
private readonly SynchronizationContext mainThreadJobSyncContext;
31+
private readonly SynchronizationContext? mainThreadJobSyncContext;
3232

3333
/// <summary>
3434
/// The collection to add all created tasks to. May be <see langword="null" />.
@@ -71,7 +71,7 @@ internal JoinableTaskFactory(JoinableTaskContext owner, JoinableTaskCollection?
7171

7272
this.owner = owner;
7373
this.jobCollection = collection;
74-
this.mainThreadJobSyncContext = new JoinableTaskSynchronizationContext(this);
74+
this.mainThreadJobSyncContext = owner.IsNoOpContext ? null : new JoinableTaskSynchronizationContext(this);
7575
}
7676

7777
/// <summary>
@@ -1017,20 +1017,23 @@ internal RunFramework(JoinableTaskFactory factory, JoinableTask joinable)
10171017
{
10181018
JoinableTaskDependencyGraph.AddDependency(this.previousJoinable, joinable);
10191019

1020-
// By definition we inherit the nesting factories of our immediate nesting task.
1021-
ListOfOftenOne<JoinableTaskFactory> nestingFactories = this.previousJoinable.NestingFactories;
1022-
1023-
// And we may add our immediate nesting parent's factory to the list of
1024-
// ancestors if it isn't already in the list.
1025-
if (this.previousJoinable.Factory != this.factory)
1020+
if (!factory.Context.IsNoOpContext)
10261021
{
1027-
if (!nestingFactories.Contains(this.previousJoinable.Factory))
1022+
// By definition we inherit the nesting factories of our immediate nesting task.
1023+
ListOfOftenOne<JoinableTaskFactory> nestingFactories = this.previousJoinable.NestingFactories;
1024+
1025+
// And we may add our immediate nesting parent's factory to the list of
1026+
// ancestors if it isn't already in the list.
1027+
if (this.previousJoinable.Factory != this.factory)
10281028
{
1029-
nestingFactories.Add(this.previousJoinable.Factory);
1029+
if (!nestingFactories.Contains(this.previousJoinable.Factory))
1030+
{
1031+
nestingFactories.Add(this.previousJoinable.Factory);
1032+
}
10301033
}
1031-
}
10321034

1033-
this.joinable.NestingFactories = nestingFactories;
1035+
this.joinable.NestingFactories = nestingFactories;
1036+
}
10341037
}
10351038

10361039
if (joinable.GetTokenizedParent() is JoinableTask tokenizedParent)

0 commit comments

Comments
 (0)