提交 c983c3ac 编写于 作者: C Cyrus Najmabadi

Process projects in parallel in FAR>

上级 558d04b3
......@@ -10,6 +10,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindSymbols.Finders;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities;
......@@ -78,33 +79,18 @@ private async Task ProcessAsync(ProjectToDocumentMap projectToDocumentMap)
return;
}
// Get the connected components of the dependency graph and process each individually.
// That way once a component is done we can throw away all the memory associated with
// it.
// For each connected component, we'll process the individual projects from bottom to
// top. i.e. we'll first process the projects with no dependencies. Then the projects
// that depend on those projects, and so on. This way we always have created the
// dependent compilations when they're needed by later projects. If we went the other
// way (i.e. processed the projects with lots of project dependencies first), then we'd
// have to create all their dependent compilations in order to get their compilation.
// This would be very expensive and would take a lot of time before we got our first
// result.
var connectedProjects = _dependencyGraph.GetDependencySets(_cancellationToken);
// Add a progress item for each (document, symbol, finder) set that we will execute.
// We'll mark the item as completed in "ProcessDocumentAsync".
var totalFindCount = projectToDocumentMap.Sum(
kvp1 => kvp1.Value.Sum(kvp2 => kvp2.Value.Count));
await _progressTracker.AddItemsAsync(totalFindCount).ConfigureAwait(false);
// Now, go through each connected project set and process it independently.
foreach (var connectedProjectSet in connectedProjects)
{
_cancellationToken.ThrowIfCancellationRequested();
using var _ = ArrayBuilder<Task>.GetInstance(out var tasks);
await ProcessProjectsAsync(
connectedProjectSet, projectToDocumentMap).ConfigureAwait(false);
}
foreach (var (project, documentMap) in projectToDocumentMap)
tasks.Add(Task.Run(() => ProcessProjectAsync(project, documentMap), _cancellationToken));
await Task.WhenAll(tasks).ConfigureAwait(false);
}
}
......
......@@ -12,72 +12,10 @@
namespace Microsoft.CodeAnalysis.FindSymbols
{
using DocumentMap = MultiDictionary<Document, (ISymbol symbol, IReferenceFinder finder)>;
using ProjectToDocumentMap = Dictionary<Project, MultiDictionary<Document, (ISymbol symbol, IReferenceFinder finder)>>;
internal partial class FindReferencesSearchEngine
{
private async Task ProcessProjectsAsync(
IEnumerable<ProjectId> connectedProjectSet,
ProjectToDocumentMap projectToDocumentMap)
{
var visitedProjects = new HashSet<ProjectId>();
// Make sure we process each project in the set. Process each project in depth first
// order. That way when we process a project, the compilations for all projects that it
// depends on will have been created already.
foreach (var projectId in connectedProjectSet)
{
_cancellationToken.ThrowIfCancellationRequested();
await ProcessProjectAsync(
projectId, projectToDocumentMap, visitedProjects).ConfigureAwait(false);
}
}
private async Task ProcessProjectAsync(
ProjectId projectId,
ProjectToDocumentMap projectToDocumentMap,
HashSet<ProjectId> visitedProjects)
{
// Don't visit projects more than once.
if (visitedProjects.Add(projectId))
{
var project = _solution.GetProject(projectId);
// Visit dependencies first. That way the compilation for a project that we depend
// on is already ready for us when we need it.
foreach (var dependent in project.ProjectReferences)
{
_cancellationToken.ThrowIfCancellationRequested();
await ProcessProjectAsync(
dependent.ProjectId, projectToDocumentMap, visitedProjects).ConfigureAwait(false);
}
await ProcessProjectAsync(project, projectToDocumentMap).ConfigureAwait(false);
}
}
private async Task ProcessProjectAsync(
Project project,
ProjectToDocumentMap projectToDocumentMap)
{
if (!projectToDocumentMap.TryGetValue(project, out var documentMap))
{
// No files in this project to process. We can bail here. We'll have cached our
// compilation if there are any projects left to process that depend on us.
return;
}
projectToDocumentMap.Remove(project);
// Now actually process the project.
await ProcessProjectAsync(project, documentMap).ConfigureAwait(false);
}
private async Task ProcessProjectAsync(
Project project,
DocumentMap documentMap)
private async Task ProcessProjectAsync(Project project, DocumentMap documentMap)
{
using (Logger.LogBlock(FunctionId.FindReference_ProcessProjectAsync, project.Name, _cancellationToken))
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册