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

Finish

上级 eecc5436
......@@ -13,6 +13,7 @@
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Editor.Tagging;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Text;
......@@ -32,7 +33,10 @@ private class Tagger : ForegroundThreadAffinitizedObject, IAccurateTagger<IClass
private TagSpanIntervalTree<IClassificationTag> _cachedTags_doNotAccessDirectly;
private SnapshotSpan? _cachedTaggedSpan_doNotAccessDirectly;
public Tagger(SemanticClassificationBufferTaggerProvider owner, ITextBuffer subjectBuffer)
public Tagger(
SemanticClassificationBufferTaggerProvider owner,
ITextBuffer subjectBuffer,
IAsynchronousOperationListener asyncListener)
: base(owner.ThreadingContext)
{
_owner = owner;
......@@ -40,7 +44,7 @@ public Tagger(SemanticClassificationBufferTaggerProvider owner, ITextBuffer subj
const TaggerDelay Delay = TaggerDelay.Short;
_eventSource = TaggerEventSources.Compose(
TaggerEventSources.OnWorkspaceChanged(subjectBuffer, Delay),
TaggerEventSources.OnWorkspaceChanged(subjectBuffer, Delay, asyncListener),
TaggerEventSources.OnDocumentActiveContextChanged(subjectBuffer, Delay));
ConnectToEventSource();
......@@ -49,9 +53,16 @@ public Tagger(SemanticClassificationBufferTaggerProvider owner, ITextBuffer subj
public void Dispose()
{
this.AssertIsForeground();
_eventSource.Changed -= OnEventSourceChanged;
_eventSource.Disconnect();
}
private void ConnectToEventSource()
{
_eventSource.Changed += OnEventSourceChanged;
_eventSource.Connect();
}
private TagSpanIntervalTree<IClassificationTag> CachedTags
{
get
......@@ -82,18 +93,14 @@ private TagSpanIntervalTree<IClassificationTag> CachedTags
}
}
private void ConnectToEventSource()
private void OnEventSourceChanged(object sender, TaggerEventArgs e)
{
_eventSource.Changed += (s, e) =>
{
_owner._notificationService.RegisterNotification((Action)OnEventSourceChanged,
_owner._asyncListener.BeginAsyncOperation("SemanticClassificationBufferTaggerProvider"));
};
_eventSource.Connect();
_owner._notificationService.RegisterNotification(
OnEventSourceChanged_OnForeground,
_owner._asyncListener.BeginAsyncOperation("SemanticClassificationBufferTaggerProvider"));
}
private void OnEventSourceChanged()
private void OnEventSourceChanged_OnForeground()
{
this.AssertIsForeground();
......
......@@ -46,7 +46,7 @@ internal partial class SemanticClassificationBufferTaggerProvider : ForegroundTh
public IAccurateTagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
{
this.AssertIsForeground();
return new Tagger(this, buffer) as IAccurateTagger<T>;
return new Tagger(this, buffer, _asyncListener) as IAccurateTagger<T>;
}
ITagger<T> ITaggerProvider.CreateTagger<T>(ITextBuffer buffer)
......
......@@ -65,7 +65,7 @@ protected override ITaggerEventSource CreateEventSource(ITextView textView, ITex
// we appear semantically unclassified for a very short amount of time.
return TaggerEventSources.Compose(
TaggerEventSources.OnViewSpanChanged(ThreadingContext, textView, textChangeDelay: Delay, scrollChangeDelay: TaggerDelay.NearImmediate),
TaggerEventSources.OnWorkspaceChanged(subjectBuffer, Delay, this.),
TaggerEventSources.OnWorkspaceChanged(subjectBuffer, Delay, this.AsyncListener),
TaggerEventSources.OnDocumentActiveContextChanged(subjectBuffer, Delay));
}
......
......@@ -57,7 +57,7 @@ protected override ITaggerEventSource CreateEventSource(ITextView textView, ITex
// reported by OnSemanticChanged.
return TaggerEventSources.Compose(
TaggerEventSources.OnCaretPositionChanged(textView, textView.TextBuffer, TaggerDelay.Short),
TaggerEventSources.OnWorkspaceChanged(subjectBuffer, TaggerDelay.OnIdle),
TaggerEventSources.OnWorkspaceChanged(subjectBuffer, TaggerDelay.OnIdle, AsyncListener),
TaggerEventSources.OnDocumentActiveContextChanged(subjectBuffer, TaggerDelay.Short));
}
......
......@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Tagging;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.VisualStudio.Text;
......@@ -14,18 +16,30 @@ internal partial class TaggerEventSources
{
private class WorkspaceChangedEventSource : AbstractWorkspaceTrackingTaggerEventSource
{
private readonly IAsynchronousOperationListener _listener;
private readonly AsyncBatchingWorkQueue<bool> _workQueue;
public WorkspaceChangedEventSource(
ITextBuffer subjectBuffer,
TaggerDelay delay,
IAsynchronousOperationListener listener)
IAsynchronousOperationListener asyncListener)
: base(subjectBuffer, delay)
{
_listener = listener;
// Batch items so that if we get a flurry of notifications, we'll only process them all once every short while.
_workQueue = new AsyncBatchingWorkQueue<bool>(
TimeSpan.FromMilliseconds(250),
)
addItemsToBatch: (batch, _) =>
{
// We only need to keep track of a single item since we don't care what type of event it was.
batch.Clear();
batch.Add(true);
},
processBatchAsync: (_1, _2) =>
{
RaiseChanged();
return Task.CompletedTask;
},
asyncListener,
CancellationToken.None);
}
protected override void ConnectToWorkspace(Workspace workspace)
......@@ -41,9 +55,7 @@ protected override void DisconnectFromWorkspace(Workspace workspace)
}
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs eventArgs)
{
RaiseChanged();
}
=> _workQueue.AddWork(true);
}
}
}
......@@ -28,9 +28,10 @@ namespace Microsoft.CodeAnalysis.Editor.Tagging
internal abstract partial class AbstractAsynchronousTaggerProvider<TTag> : ForegroundThreadAffinitizedObject where TTag : ITag
{
private readonly object _uniqueKey = new object();
private readonly IAsynchronousOperationListener _asyncListener;
private readonly IForegroundNotificationService _notificationService;
protected readonly IAsynchronousOperationListener AsyncListener;
/// <summary>
/// The behavior the tagger engine will have when text changes happen to the subject buffer
/// it is attached to. Most taggers can simply use <see cref="TaggerTextChangeBehavior.None"/>.
......@@ -94,7 +95,7 @@ internal abstract partial class AbstractAsynchronousTaggerProvider<TTag> : Foreg
IForegroundNotificationService notificationService)
: base(threadingContext)
{
_asyncListener = asyncListener;
AsyncListener = asyncListener;
_notificationService = notificationService;
#if DEBUG
......@@ -110,14 +111,14 @@ internal abstract partial class AbstractAsynchronousTaggerProvider<TTag> : Foreg
}
var tagSource = GetOrCreateTagSource(textViewOpt, subjectBuffer);
return new Tagger(ThreadingContext, _asyncListener, _notificationService, tagSource, subjectBuffer) as IAccurateTagger<T>;
return new Tagger(ThreadingContext, AsyncListener, _notificationService, tagSource, subjectBuffer) as IAccurateTagger<T>;
}
private TagSource GetOrCreateTagSource(ITextView textViewOpt, ITextBuffer subjectBuffer)
{
if (!this.TryRetrieveTagSource(textViewOpt, subjectBuffer, out var tagSource))
{
tagSource = new TagSource(textViewOpt, subjectBuffer, this, _asyncListener, _notificationService);
tagSource = new TagSource(textViewOpt, subjectBuffer, this, AsyncListener, _notificationService);
this.StoreTagSource(textViewOpt, subjectBuffer, tagSource);
tagSource.Disposed += (s, e) => this.RemoveTagSource(textViewOpt, subjectBuffer);
......
......@@ -24,6 +24,7 @@
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell.Services;
using Microsoft.VisualStudio.Telemetry;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribute
......@@ -316,7 +317,10 @@ private void AddFilteredInfos(ImmutableArray<DesignerAttributeData> data, ArrayB
public Task ReportDesignerAttributeDataAsync(ImmutableArray<DesignerAttributeData> data, CancellationToken cancellationToken)
{
Contract.ThrowIfNull(_workQueue);
_workQueue.AddWork(data);
using var _ = ArrayBuilder<DesignerAttributeData>.GetInstance(out var temp);
temp.AddRange(data);
_workQueue.AddWork(temp);
return Task.CompletedTask;
}
......
......@@ -139,4 +139,7 @@
<Import Project="..\..\..\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems" Label="Shared" />
<Import Project="..\..\..\Workspaces\SharedUtilitiesAndExtensions\Compiler\Core\CompilerExtensions.projitems" Label="Shared" />
<Import Project="..\..\..\Workspaces\SharedUtilitiesAndExtensions\Workspace\Core\WorkspaceExtensions.projitems" Label="Shared" />
<ItemGroup>
<ExpectedCompile Remove="Shared\Utilities\AsyncBatchingWorkQueue.cs" />
</ItemGroup>
</Project>
......@@ -7,9 +7,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.TestHooks;
namespace Roslyn.Utilities
{
......@@ -21,15 +23,23 @@ namespace Roslyn.Utilities
/// </summary>
internal class AsyncBatchingWorkQueue<TItem>
{
public delegate void AddItemsToBatch(ArrayBuilder<TItem> batch, ArrayBuilder<TItem> newItems);
/// <summary>
/// Delay we wait after finishing the processing of one batch and starting up on then.
/// </summary>
private readonly TimeSpan _delay;
/// <summary>
/// Callback that actually adds items to the current batch.
/// </summary>
private readonly AsyncBatchingWorkQueue<TItem>.AddItemsToBatch _addItemsToBatch;
/// <summary>
/// Callback to actually perform the processing of the next batch of work.
/// </summary>
private readonly Func<ImmutableArray<TItem>, CancellationToken, Task> _processBatchAsync;
private readonly IAsynchronousOperationListener? _asyncListener;
private readonly CancellationToken _cancellationToken;
#region protected by lock
......@@ -45,7 +55,7 @@ internal class AsyncBatchingWorkQueue<TItem>
/// <summary>
/// Data added that we want to process in our next update task.
/// </summary>
private readonly List<TItem> _nextBatch = new List<TItem>();
private readonly ArrayBuilder<TItem> _nextBatch = ArrayBuilder<TItem>.GetInstance();
/// <summary>
/// Task kicked off to do the next batch of processing of <see cref="_nextBatch"/>. These
......@@ -66,9 +76,27 @@ internal class AsyncBatchingWorkQueue<TItem>
TimeSpan delay,
Func<ImmutableArray<TItem>, CancellationToken, Task> processBatchAsync,
CancellationToken cancellationToken)
: this(delay,
(batch, items) => batch.AddRange(items),
processBatchAsync,
asyncListener: null,
cancellationToken)
{
}
/// <param name="processBatchAsync">Callback to add the new items to the current batch. It is legal to mutate
/// the current batch (for example, clearing the batch or deduplicating)</param>
public AsyncBatchingWorkQueue(
TimeSpan delay,
AddItemsToBatch addItemsToBatch,
Func<ImmutableArray<TItem>, CancellationToken, Task> processBatchAsync,
IAsynchronousOperationListener? asyncListener,
CancellationToken cancellationToken)
{
_delay = delay;
_addItemsToBatch = addItemsToBatch;
_processBatchAsync = processBatchAsync;
_asyncListener = asyncListener;
_cancellationToken = cancellationToken;
}
......@@ -80,7 +108,7 @@ public void AddWork(TItem item)
AddWork(items);
}
public void AddWork(IEnumerable<TItem> items)
public void AddWork(ArrayBuilder<TItem> items)
{
// Don't do any more work if we've been asked to shutdown.
if (_cancellationToken.IsCancellationRequested)
......@@ -89,21 +117,7 @@ public void AddWork(IEnumerable<TItem> items)
lock (_gate)
{
// add our work to the set we'll process in the next batch.
_nextBatch.AddRange(items);
TryKickOffNextBatchTask();
}
}
public void AddWork(ImmutableArray<TItem> items)
{
// Don't do any more work if we've been asked to shutdown.
if (_cancellationToken.IsCancellationRequested)
return;
lock (_gate)
{
// add our work to the set we'll process in the next batch.
_nextBatch.AddRange(items);
_addItemsToBatch(batch: _nextBatch, newItems: items);
TryKickOffNextBatchTask();
}
}
......@@ -115,12 +129,15 @@ private void TryKickOffNextBatchTask()
// No in-flight task. Kick one off to process these messages a second from now.
// We always attach the task to the previous one so that notifications to the ui
// follow the same order as the notification the OOP server sent to us.
var token = _asyncListener?.BeginAsyncOperation(nameof(TryKickOffNextBatchTask));
_updateTask = _updateTask.ContinueWithAfterDelayFromAsync(
_ => ProcessNextBatchAsync(_cancellationToken),
_cancellationToken,
(int)_delay.TotalMilliseconds,
TaskContinuationOptions.RunContinuationsAsynchronously,
TaskScheduler.Default);
TaskScheduler.Default).CompletesAsyncOperation(token);
_taskInFlight = true;
}
}
......
......@@ -339,7 +339,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Utilities\AbstractSpeculationAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\AliasSymbolCache.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\AnnotationTable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\AsyncBatchingWorkQueue.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\AsyncLazy`1.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\BidirectionalMap.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\BKTree.Builder.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册