Có hai điều bạn nên làm:
- Set
InternalBufferSize
đến mức tối đa giá trị hỗ trợ (65536). Nỗ lực của bạn để đặt thành "8192 * 128" lớn hơn giá trị được hỗ trợ tối đa được liệt kê trong documentation, vì vậy bạn có thể không tăng kích thước bộ đệm.
- Sự kiện xếp hàng từ
FileSystemWatcher
vào chuỗi nền để xử lý.
Đây là điểm thứ hai ở đây không được hiểu rõ và thực sự cần được ghi lại trên MSDN. Bên trong, FileSystemWatcher
đang xếp hàng các sự kiện thay đổi vào bộ đệm trong đó bạn đặt kích thước ở trên. Tuy nhiên, các mục chỉ bị xóa khỏi bộ đệm sau khi trình xử lý sự kiện của bạn trả về. Điều này có nghĩa là mọi chu kỳ của việc xử lý sự kiện trên đầu của bạn sẽ làm tăng khả năng đệm lấp đầy. Những gì bạn cần làm là xóa hàng đợi có giới hạn của FileSystemWatcher
càng nhanh càng tốt và di chuyển các sự kiện vào hàng đợi vô hạn của riêng bạn, để xử lý ở tốc độ bạn có thể xử lý hoặc loại bỏ nếu bạn quan tâm, nhưng với một số thông tin xung quanh nó.
Đây là những gì tôi làm trong mã của mình. Trước tiên, tôi bắt đầu chuỗi điều phối của riêng mình:
Dispatcher changeDispatcher = null;
ManualResetEvent changeDispatcherStarted = new ManualResetEvent(false);
Action changeThreadHandler =() =>
{
changeDispatcher = Dispatcher.CurrentDispatcher;
changeDispatcherStarted.Set();
Dispatcher.Run();
};
new Thread(() => changeThreadHandler()) { IsBackground = true }.Start();
changeDispatcherStarted.WaitOne();
Sau đó, tôi tạo trình theo dõi. Lưu ý kích thước bộ đệm được thiết lập. Trong trường hợp của tôi, tôi chỉ xem những thay đổi trong thư mục đích, không phải thư mục con:
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = path;
watcher.InternalBufferSize = 64 * 1024;
watcher.IncludeSubdirectories = false;
Bây giờ tôi đính kèm xử lý sự kiện của tôi, nhưng ở đây tôi gọi chúng vào điều phối của tôi thay vì chạy chúng đồng bộ trong các chủ đề quan sát. Vâng, các sự kiện sẽ được xử lý theo thứ tự của các điều phối:
watcher.Changed += (sender, e) => changeDispatcher.BeginInvoke(new Action(() => OnChanged(sender, e)));
watcher.Created += (sender, e) => changeDispatcher.BeginInvoke(new Action(() => OnCreated(sender, e)));
watcher.Deleted += (sender, e) => changeDispatcher.BeginInvoke(new Action(() => OnDeleted(sender, e)));
watcher.Renamed += (sender, e) => changeDispatcher.BeginInvoke(new Action(() => OnRenamed(sender, e)));
Và cuối cùng, sau khi xử lý các FileSystemWatcher
(? Bạn đã làm điều đó, bên phải), bạn cần phải tắt phối của bạn:
watcher.Dispose()
changeDispatcher.BeginInvokeShutdown(DispatcherPriority.Normal);
Và đó là nó. Tôi đã nhận được vấn đề này bản thân mình, cả trong các kịch bản mạng và địa phương. Sau khi sử dụng cách tiếp cận này, tôi đã không thể tạo lại lỗi này, ngay cả khi đang bung ra các tệp rỗng để xem các thư mục nhanh nhất có thể. Nếu bạn đã từng quản lý bằng cách nào đó xả bộ đệm trong trường hợp này (mà tôi không chắc chắn là có thể, API thượng nguồn có lẽ là chậm hơn), vẫn còn có chỗ để tối ưu hóa ở đây. Miễn là dispatcher của bạn là qua "điểm tới hạn", mặc dù, người gửi không thể gửi các sự kiện nhanh hơn bạn có thể gửi chúng, bạn sẽ không bao giờ nhận được một backlog, và do đó không bao giờ thổi bộ đệm. Tôi tin rằng cách tiếp cận này đặt bạn vào khu vực an toàn đó.
Tôi đã chỉnh sửa tiêu đề của bạn. Vui lòng xem, "[Câu hỏi có nên bao gồm" thẻ "trong tiêu đề của họ không?] (Http://meta.stackexchange.com/questions/19190/)", trong đó sự đồng thuận là "không, họ không nên". –