Tôi đang làm việc trên một hệ thống mô phỏng, trong số những thứ khác, cho phép thực hiện các tác vụ trong các bước thời gian mô phỏng rời rạc. Việc thực hiện tất cả xảy ra trong ngữ cảnh của chuỗi mô phỏng, nhưng, từ quan điểm của một toán tử '' sử dụng hệ thống, chúng muốn hành xử không đồng bộ. Rất may là TPL, với các từ khóa 'không đồng bộ/chờ đợi' tiện dụng, làm cho điều này khá đơn giản. Tôi có một phương pháp nguyên thủy trên Mô phỏng như sau:Các công việc báo hiệu hiệu quả cho việc hoàn thành TPL trên các sự kiện thường xuyên reoccuring
public Task CycleExecutedEvent()
{
lock (_cycleExecutedBroker)
{
if (!IsRunning) throw new TaskCanceledException("Simulation has been stopped");
return _cycleExecutedBroker.RegisterForCompletion(CycleExecutedEventName);
}
}
Điều này về cơ bản là tạo một TaskCompletionSource mới và sau đó trả lại một Tác vụ. Mục đích của nhiệm vụ này là thực hiện sự tiếp tục của nó khi 'ExecuteCycle' mới trên mô phỏng xảy ra.
sau đó tôi có một số phương pháp mở rộng như thế này:
public static async Task WaitForDuration(this ISimulation simulation, double duration)
{
double startTime = simulation.CurrentSimulatedTime;
do
{
await simulation.CycleExecutedEvent();
} while ((simulation.CurrentSimulatedTime - startTime) < duration);
}
public static async Task WaitForCondition(this ISimulation simulation, Func<bool> condition)
{
do
{
await simulation.CycleExecutedEvent();
} while (!condition());
}
Đây là rất tiện dụng, sau đó, để xây dựng chuỗi từ một góc độ 'điều hành', có những hành động dựa trên điều kiện và chờ đợi khoảng thời gian mô phỏng. Vấn đề tôi đang chạy vào là CycleExecuted xảy ra rất thường xuyên (khoảng mỗi vài phần nghìn giây nếu tôi đang chạy ở tốc độ hoàn toàn tăng tốc). Bởi vì các phương thức trợ giúp 'chờ' này đăng ký một 'await' mới trên mỗi chu kỳ, điều này gây ra doanh thu lớn trong các thể hiện của TaskCompletionSource.
Tôi đã lược tả mã của mình và tôi thấy rằng khoảng 5,5% tổng thời gian CPU của tôi được chi tiêu trong các lần hoàn thành này, trong đó chỉ một phần trăm không đáng kể được chi tiêu trong mã 'hoạt động'. Có hiệu quả tất cả thời gian được dành để đăng ký các lần hoàn thành mới trong khi đợi các điều kiện kích hoạt hợp lệ.
Câu hỏi của tôi: làm cách nào để cải thiện hiệu suất tại đây trong khi vẫn giữ được sự tiện lợi của mẫu không đồng bộ/chờ đợi để viết 'hành vi của nhà điều hành'? Tôi nghĩ rằng tôi cần một cái gì đó như một TaskCompletionSource trọng lượng nhẹ hơn và/hoặc tái sử dụng, cho rằng sự kiện kích hoạt xảy ra thường xuyên.
Tôi đã thực hiện một nghiên cứu thêm chút và có vẻ như là một lựa chọn tốt sẽ tạo ra một thực hiện tùy chỉnh các mô hình Awaitable, mà có thể buộc trực tiếp vào sự kiện này, loại bỏ sự cần thiết cho một loạt các Các trường hợp TaskCompletionSource và Task. Lý do nó có thể hữu ích ở đây là có rất nhiều sự tiếp tục khác nhau đang đợi CycleExecutedEvent và chúng cần phải chờ nó thường xuyên. Vì vậy, lý tưởng tôi đang xem xét một cách để chỉ xếp hàng các cuộc gọi lại tiếp tục, sau đó gọi lại mọi thứ trong hàng đợi bất cứ khi nào sự kiện xảy ra. Tôi sẽ tiếp tục đào bới, nhưng tôi hoan nghênh mọi sự giúp đỡ nếu mọi người biết cách làm sạch.
Đối với bất cứ ai xem câu hỏi này trong tương lai, đây là tùy chỉnh awaiter tôi đặt lại với nhau:
public sealed class CycleExecutedAwaiter : INotifyCompletion
{
private readonly List<Action> _continuations = new List<Action>();
public bool IsCompleted
{
get { return false; }
}
public void GetResult()
{
}
public void OnCompleted(Action continuation)
{
_continuations.Add(continuation);
}
public void RunContinuations()
{
var continuations = _continuations.ToArray();
_continuations.Clear();
foreach (var continuation in continuations)
continuation();
}
public CycleExecutedAwaiter GetAwaiter()
{
return this;
}
}
Và trong Simulator:
private readonly CycleExecutedAwaiter _cycleExecutedAwaiter = new CycleExecutedAwaiter();
public CycleExecutedAwaiter CycleExecutedEvent()
{
if (!IsRunning) throw new TaskCanceledException("Simulation has been stopped");
return _cycleExecutedAwaiter;
}
Đó là một chút buồn cười, như người chờ đợi không bao giờ báo cáo Hoàn thành, nhưng hỏa hoạn tiếp tục gọi số lần hoàn thành khi chúng được đăng ký; nó vẫn hoạt động tốt cho ứng dụng này. Điều này làm giảm chi phí CPU từ 5,5% xuống 2,1%. Nó có thể sẽ vẫn yêu cầu một số tinh chỉnh, nhưng đó là một cải tiến tốt đẹp so với bản gốc.
Xin chào, không công bằng khi trả lời câu hỏi của riêng bạn một phút trước tôi! :-) – svick
@svick, chưa được trả lời đầy đủ; Tôi vẫn cần phải tìm ra cách tạo ra tùy chỉnh chờ đợi. :) Cảm ơn các liên kết; chúng khá hữu ích. –
@DanBryant: bạn nên trả lời câu hỏi của bạn ... như là một câu trả lời chứ không phải là trong cơ thể của câu hỏi của riêng bạn. – user7116