提交 865a19cf 编写于 作者: C Cyrus Najmabadi

Make the IWorkCoordinatorPriorityService async and appropriately cascade out the asynchrony.

Originally this was synchronous because it was used through codepaths that all were
inherently synchronous.  Over the last year the WorkCoordinator has become increasingly
async, and we're now at the point where this API can be async too.  This is a win for
TypeScript because we have to currently implement this API in blocking fashion.  This
has shown up in profiles, and making it async should be a nice win for us.
上级 341215ac
......@@ -16,6 +16,6 @@ internal interface IWorkCoordinatorPriorityService : ILanguageService
/// contained in, and should have work scheduled for it happen after all other documents
/// in the project.
/// </summary>
bool IsLowPriority(Document document);
Task<bool> IsLowPriorityAsync(Document document);
}
}
......@@ -107,11 +107,11 @@ private async Task<bool> TryEnqueueFromHint(Document document, SyntaxPath change
return false;
}
return TryEnqueueFromMember(document, symbol) ||
TryEnqueueFromType(document, symbol);
return await TryEnqueueFromMemberAsync(document, symbol).ConfigureAwait(false) ||
await TryEnqueueFromTypeAsync(document, symbol).ConfigureAwait(false);
}
private bool TryEnqueueFromType(Document document, ISymbol symbol)
private async Task<bool> TryEnqueueFromTypeAsync(Document document, ISymbol symbol)
{
if (!IsType(symbol))
{
......@@ -120,7 +120,7 @@ private bool TryEnqueueFromType(Document document, ISymbol symbol)
if (symbol.DeclaredAccessibility == Accessibility.Private)
{
EnqueueWorkItem(document, symbol);
await EnqueueWorkItemAsync(document, symbol).ConfigureAwait(false);
Logger.Log(FunctionId.WorkCoordinator_SemanticChange_EnqueueFromType, symbol.Name);
return true;
......@@ -136,7 +136,7 @@ private bool TryEnqueueFromType(Document document, ISymbol symbol)
return false;
}
private bool TryEnqueueFromMember(Document document, ISymbol symbol)
private async Task<bool> TryEnqueueFromMemberAsync(Document document, ISymbol symbol)
{
if (!IsMember(symbol))
{
......@@ -147,7 +147,7 @@ private bool TryEnqueueFromMember(Document document, ISymbol symbol)
if (symbol.DeclaredAccessibility == Accessibility.Private)
{
EnqueueWorkItem(document, symbol);
await EnqueueWorkItemAsync(document, symbol).ConfigureAwait(false);
Logger.Log(FunctionId.WorkCoordinator_SemanticChange_EnqueueFromMember, symbol.Name);
return true;
......@@ -158,15 +158,15 @@ private bool TryEnqueueFromMember(Document document, ISymbol symbol)
return false;
}
return TryEnqueueFromType(document, typeSymbol);
return await TryEnqueueFromTypeAsync(document, typeSymbol).ConfigureAwait(false);
}
private void EnqueueWorkItem(Document document, ISymbol symbol)
private Task EnqueueWorkItemAsync(Document document, ISymbol symbol)
{
EnqueueWorkItem(document, symbol.ContainingType != null ? symbol.ContainingType.Locations : symbol.Locations);
return EnqueueWorkItemAsync(document, symbol.ContainingType != null ? symbol.ContainingType.Locations : symbol.Locations);
}
private void EnqueueWorkItem(Document thisDocument, ImmutableArray<Location> locations)
private async Task EnqueueWorkItemAsync(Document thisDocument, ImmutableArray<Location> locations)
{
var solution = thisDocument.Project.Solution;
var projectId = thisDocument.Id.ProjectId;
......@@ -183,7 +183,7 @@ private void EnqueueWorkItem(Document thisDocument, ImmutableArray<Location> loc
continue;
}
_processor.EnqueueWorkItem(document);
await _processor.EnqueueWorkItemAsync(document).ConfigureAwait(false);
}
}
......@@ -356,17 +356,18 @@ public void Enqueue(ProjectId projectId, bool needDependencyTracking = false)
Logger.Log(FunctionId.WorkCoordinator_Project_Enqueue, s_enqueueLogger, Environment.TickCount, projectId);
}
public void EnqueueWorkItem(Document document)
public async Task EnqueueWorkItemAsync(Document document)
{
// we are shutting down
this.CancellationToken.ThrowIfCancellationRequested();
// call to this method is serialized. and only this method does the writing.
var priorityService = document.GetLanguageService<IWorkCoordinatorPriorityService>();
var isLowPriority = priorityService != null && await priorityService.IsLowPriorityAsync(document).ConfigureAwait(false);
_processor.Enqueue(
new WorkItem(document.Id, document.Project.Language, InvocationReasons.SemanticChanged,
priorityService != null && priorityService.IsLowPriority(document),
this.Listener.BeginAsyncOperation("Semantic WorkItem")));
isLowPriority, this.Listener.BeginAsyncOperation("Semantic WorkItem")));
}
protected override Task WaitAsync(CancellationToken cancellationToken)
......@@ -374,36 +375,33 @@ protected override Task WaitAsync(CancellationToken cancellationToken)
return _gate.WaitAsync(cancellationToken);
}
protected override Task ExecuteAsync()
protected override async Task ExecuteAsync()
{
var data = Dequeue();
var project = _registration.CurrentSolution.GetProject(data.ProjectId);
if (project == null)
using (data.AsyncToken)
{
data.AsyncToken.Dispose();
return SpecializedTasks.EmptyTask;
}
var project = _registration.CurrentSolution.GetProject(data.ProjectId);
if (project == null)
{
return;
}
if (!data.NeedDependencyTracking)
{
EnqueueWorkItem(project);
data.AsyncToken.Dispose();
return SpecializedTasks.EmptyTask;
}
if (!data.NeedDependencyTracking)
{
await EnqueueWorkItemAsync(project).ConfigureAwait(false);
return;
}
// do dependency tracking here with current solution
var solution = _registration.CurrentSolution;
// do dependency tracking here with current solution
var solution = _registration.CurrentSolution;
var graph = solution.GetProjectDependencyGraph();
foreach (var projectId in graph.GetProjectsThatTransitivelyDependOnThisProject(data.ProjectId).Concat(data.ProjectId))
{
project = solution.GetProject(projectId);
EnqueueWorkItem(project);
var graph = solution.GetProjectDependencyGraph();
foreach (var projectId in graph.GetProjectsThatTransitivelyDependOnThisProject(data.ProjectId).Concat(data.ProjectId))
{
project = solution.GetProject(projectId);
await EnqueueWorkItemAsync(project).ConfigureAwait(false);
}
}
data.AsyncToken.Dispose();
return SpecializedTasks.EmptyTask;
}
private Data Dequeue()
......@@ -411,7 +409,7 @@ private Data Dequeue()
return DequeueWorker(_workGate, _pendingWork, this.CancellationToken);
}
private void EnqueueWorkItem(Project project)
private async Task EnqueueWorkItemAsync(Project project)
{
if (project == null)
{
......@@ -420,7 +418,7 @@ private void EnqueueWorkItem(Project project)
foreach (var documentId in project.DocumentIds)
{
EnqueueWorkItem(project.GetDocument(documentId));
await EnqueueWorkItemAsync(project.GetDocument(documentId)).ConfigureAwait(false);
}
}
......
......@@ -166,7 +166,7 @@ public void Reanalyze(IIncrementalAnalyzer analyzer, IEnumerable<DocumentId> doc
{
var asyncToken = _listener.BeginAsyncOperation("Reanalyze");
_eventProcessingQueue.ScheduleTask(
() => EnqueueWorkItem(analyzer, documentIds), _shutdownToken).CompletesAsyncOperation(asyncToken);
() => EnqueueWorkItemAsync(analyzer, documentIds), _shutdownToken).CompletesAsyncOperation(asyncToken);
SolutionCrawlerLogger.LogReanalyze(CorrelationId, analyzer, documentIds);
}
......@@ -247,14 +247,14 @@ private void OnDocumentOpened(object sender, DocumentEventArgs e)
{
var asyncToken = _listener.BeginAsyncOperation("OnDocumentOpened");
_eventProcessingQueue.ScheduleTask(
() => EnqueueWorkItem(e.Document, InvocationReasons.DocumentOpened), _shutdownToken).CompletesAsyncOperation(asyncToken);
() => EnqueueWorkItemAsync(e.Document, InvocationReasons.DocumentOpened), _shutdownToken).CompletesAsyncOperation(asyncToken);
}
private void OnDocumentClosed(object sender, DocumentEventArgs e)
{
var asyncToken = _listener.BeginAsyncOperation("OnDocumentClosed");
_eventProcessingQueue.ScheduleTask(
() => EnqueueWorkItem(e.Document, InvocationReasons.DocumentClosed), _shutdownToken).CompletesAsyncOperation(asyncToken);
() => EnqueueWorkItemAsync(e.Document, InvocationReasons.DocumentClosed), _shutdownToken).CompletesAsyncOperation(asyncToken);
}
private void ProcessDocumentEvent(WorkspaceChangeEventArgs e, IAsyncToken asyncToken)
......@@ -362,8 +362,8 @@ private void EnqueueEvent(Solution oldSolution, Solution newSolution, IAsyncToke
private void EnqueueEvent(Solution solution, InvocationReasons invocationReasons, IAsyncToken asyncToken)
{
var task = _eventProcessingQueue.ScheduleTask(
() => EnqueueWorkItemForSolution(solution, invocationReasons), _shutdownToken).CompletesAsyncOperation(asyncToken);
_eventProcessingQueue.ScheduleTask(
() => EnqueueWorkItemForSolutionAsync(solution, invocationReasons), _shutdownToken).CompletesAsyncOperation(asyncToken);
}
private void EnqueueEvent(Solution oldSolution, Solution newSolution, ProjectId projectId, IAsyncToken asyncToken)
......@@ -375,13 +375,13 @@ private void EnqueueEvent(Solution oldSolution, Solution newSolution, ProjectId
private void EnqueueEvent(Solution solution, ProjectId projectId, InvocationReasons invocationReasons, IAsyncToken asyncToken)
{
_eventProcessingQueue.ScheduleTask(
() => EnqueueWorkItemForProject(solution, projectId, invocationReasons), _shutdownToken).CompletesAsyncOperation(asyncToken);
() => EnqueueWorkItemForProjectAsync(solution, projectId, invocationReasons), _shutdownToken).CompletesAsyncOperation(asyncToken);
}
private void EnqueueEvent(Solution solution, DocumentId documentId, InvocationReasons invocationReasons, IAsyncToken asyncToken)
{
_eventProcessingQueue.ScheduleTask(
() => EnqueueWorkItemForDocument(solution, documentId, invocationReasons), _shutdownToken).CompletesAsyncOperation(asyncToken);
() => EnqueueWorkItemForDocumentAsync(solution, documentId, invocationReasons), _shutdownToken).CompletesAsyncOperation(asyncToken);
}
private void EnqueueEvent(Solution oldSolution, Solution newSolution, DocumentId documentId, IAsyncToken asyncToken)
......@@ -391,20 +391,20 @@ private void EnqueueEvent(Solution oldSolution, Solution newSolution, DocumentId
() => EnqueueWorkItemAfterDiffAsync(oldSolution, newSolution, documentId), _shutdownToken).CompletesAsyncOperation(asyncToken);
}
private void EnqueueWorkItem(Document document, InvocationReasons invocationReasons, SyntaxNode changedMember = null)
private async Task EnqueueWorkItemAsync(Document document, InvocationReasons invocationReasons, SyntaxNode changedMember = null)
{
// we are shutting down
_shutdownToken.ThrowIfCancellationRequested();
var priorityService = document.GetLanguageService<IWorkCoordinatorPriorityService>();
var isLowPriority = priorityService != null && await priorityService.IsLowPriorityAsync(document).ConfigureAwait(false);
var currentMember = GetSyntaxPath(changedMember);
// call to this method is serialized. and only this method does the writing.
_documentAndProjectWorkerProcessor.Enqueue(
new WorkItem(document.Id, document.Project.Language, invocationReasons,
priorityService != null && priorityService.IsLowPriority(document),
currentMember, _listener.BeginAsyncOperation("WorkItem")));
isLowPriority, currentMember, _listener.BeginAsyncOperation("WorkItem")));
// enqueue semantic work planner
if (invocationReasons.Contains(PredefinedInvocationReasons.SemanticChanged))
......@@ -427,16 +427,16 @@ private SyntaxPath GetSyntaxPath(SyntaxNode changedMember)
return new SyntaxPath(changedMember);
}
private void EnqueueWorkItem(Project project, InvocationReasons invocationReasons)
private async Task EnqueueWorkItemAsync(Project project, InvocationReasons invocationReasons)
{
foreach (var documentId in project.DocumentIds)
{
var document = project.GetDocument(documentId);
EnqueueWorkItem(document, invocationReasons);
await EnqueueWorkItemAsync(document, invocationReasons).ConfigureAwait(false);
}
}
private void EnqueueWorkItem(IIncrementalAnalyzer analyzer, IEnumerable<DocumentId> documentIds)
private async Task EnqueueWorkItemAsync(IIncrementalAnalyzer analyzer, IEnumerable<DocumentId> documentIds)
{
var solution = _registration.CurrentSolution;
foreach (var documentId in documentIds)
......@@ -448,11 +448,11 @@ private void EnqueueWorkItem(IIncrementalAnalyzer analyzer, IEnumerable<Document
}
var priorityService = document.GetLanguageService<IWorkCoordinatorPriorityService>();
var isLowPriority = priorityService != null && await priorityService.IsLowPriorityAsync(document).ConfigureAwait(false);
_documentAndProjectWorkerProcessor.Enqueue(
new WorkItem(documentId, document.Project.Language, InvocationReasons.Reanalyze,
priorityService != null && priorityService.IsLowPriority(document),
analyzer, _listener.BeginAsyncOperation("WorkItem")));
isLowPriority, analyzer, _listener.BeginAsyncOperation("WorkItem")));
}
}
......@@ -463,7 +463,7 @@ private async Task EnqueueWorkItemAsync(Solution oldSolution, Solution newSoluti
// TODO: Async version for GetXXX methods?
foreach (var addedProject in solutionChanges.GetAddedProjects())
{
EnqueueWorkItem(addedProject, InvocationReasons.DocumentAdded);
await EnqueueWorkItemAsync(addedProject, InvocationReasons.DocumentAdded).ConfigureAwait(false);
}
foreach (var projectChanges in solutionChanges.GetProjectChanges())
......@@ -473,17 +473,17 @@ private async Task EnqueueWorkItemAsync(Solution oldSolution, Solution newSoluti
foreach (var removedProject in solutionChanges.GetRemovedProjects())
{
EnqueueWorkItem(removedProject, InvocationReasons.DocumentRemoved);
await EnqueueWorkItemAsync(removedProject, InvocationReasons.DocumentRemoved).ConfigureAwait(false);
}
}
private async Task EnqueueWorkItemAsync(ProjectChanges projectChanges)
{
EnqueueProjectConfigurationChangeWorkItem(projectChanges);
await EnqueueProjectConfigurationChangeWorkItemAsync(projectChanges).ConfigureAwait(false);
foreach (var addedDocumentId in projectChanges.GetAddedDocuments())
{
EnqueueWorkItem(projectChanges.NewProject.GetDocument(addedDocumentId), InvocationReasons.DocumentAdded);
await EnqueueWorkItemAsync(projectChanges.NewProject.GetDocument(addedDocumentId), InvocationReasons.DocumentAdded).ConfigureAwait(false);
}
foreach (var changedDocumentId in projectChanges.GetChangedDocuments())
......@@ -494,11 +494,11 @@ await EnqueueWorkItemAsync(projectChanges.OldProject.GetDocument(changedDocument
foreach (var removedDocumentId in projectChanges.GetRemovedDocuments())
{
EnqueueWorkItem(projectChanges.OldProject.GetDocument(removedDocumentId), InvocationReasons.DocumentRemoved);
await EnqueueWorkItemAsync(projectChanges.OldProject.GetDocument(removedDocumentId), InvocationReasons.DocumentRemoved).ConfigureAwait(false);
}
}
private void EnqueueProjectConfigurationChangeWorkItem(ProjectChanges projectChanges)
private async Task EnqueueProjectConfigurationChangeWorkItemAsync(ProjectChanges projectChanges)
{
var oldProject = projectChanges.OldProject;
var newProject = projectChanges.NewProject;
......@@ -520,7 +520,7 @@ private void EnqueueProjectConfigurationChangeWorkItem(ProjectChanges projectCha
if (!projectConfigurationChange.IsEmpty)
{
EnqueueWorkItem(projectChanges.NewProject, projectConfigurationChange);
await EnqueueWorkItemAsync(projectChanges.NewProject, projectConfigurationChange).ConfigureAwait(false);
}
}
......@@ -533,30 +533,30 @@ private async Task EnqueueWorkItemAsync(Document oldDocument, Document newDocume
if (differenceResult != null)
{
EnqueueWorkItem(newDocument, differenceResult.ChangeType, differenceResult.ChangedMember);
await EnqueueWorkItemAsync(newDocument, differenceResult.ChangeType, differenceResult.ChangedMember).ConfigureAwait(false);
}
}
}
private void EnqueueWorkItemForDocument(Solution solution, DocumentId documentId, InvocationReasons invocationReasons)
private Task EnqueueWorkItemForDocumentAsync(Solution solution, DocumentId documentId, InvocationReasons invocationReasons)
{
var document = solution.GetDocument(documentId);
EnqueueWorkItem(document, invocationReasons);
return EnqueueWorkItemAsync(document, invocationReasons);
}
private void EnqueueWorkItemForProject(Solution solution, ProjectId projectId, InvocationReasons invocationReasons)
private Task EnqueueWorkItemForProjectAsync(Solution solution, ProjectId projectId, InvocationReasons invocationReasons)
{
var project = solution.GetProject(projectId);
EnqueueWorkItem(project, invocationReasons);
return EnqueueWorkItemAsync(project, invocationReasons);
}
private void EnqueueWorkItemForSolution(Solution solution, InvocationReasons invocationReasons)
private async Task EnqueueWorkItemForSolutionAsync(Solution solution, InvocationReasons invocationReasons)
{
foreach (var projectId in solution.ProjectIds)
{
EnqueueWorkItemForProject(solution, projectId, invocationReasons);
await EnqueueWorkItemForProjectAsync(solution, projectId, invocationReasons).ConfigureAwait(false);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册