Khi yêu cầu Queue.Synchonized
bạn nhận được một số SynchronizedQueue
đổi lại sử dụng số lock
rất tối thiểu xung quanh các cuộc gọi đến Enqueue
và Dequeue
trên hàng đợi bên trong. Do đó, hiệu suất phải giống như việc sử dụng số Queue
và tự quản lý khóa cho Enqueue
và Dequeue
với số lock
của riêng bạn.
Bạn thực sự đang tưởng tượng mọi thứ - chúng phải giống nhau.
Cập nhật
Có thực sự là một thực tế rằng khi sử dụng một SynchronizedQueue
bạn đang thêm một lớp về mình như bạn phải đi qua các phương pháp wrapper để có được vào hàng đợi bên trong mà nó đang quản lý. Nếu bất cứ điều gì này nên làm chậm những thứ xuống rất phân đoạn như bạn đã có một khung phụ trên ngăn xếp mà cần phải được quản lý cho mỗi cuộc gọi. Thiên Chúa biết nếu trong lót hủy bỏ điều này mặc dù. Bất cứ điều gì - đó là tối thiểu.
Cập nhật 2
Bây giờ tôi đã làm chuẩn này, và như dự đoán trong bản cập nhật trước đây của tôi:
"Queue.Synchronized" là chậm hơn so với "Queue + khóa"
Tôi thực hiện một thử nghiệm đơn luồng vì cả hai đều sử dụng kỹ thuật khóa tương tự (ví dụ lock
) để kiểm tra chi phí tinh khiết trong một "đường thẳng" có vẻ hợp lý.
benchmark của tôi tạo ra kết quả như sau cho một phát hành xây dựng:
Iterations :10,000,000
Queue+Lock :539.14ms
Queue+Lock :540.55ms
Queue+Lock :539.46ms
Queue+Lock :540.46ms
Queue+Lock :539.75ms
SynchonizedQueue:578.67ms
SynchonizedQueue:585.04ms
SynchonizedQueue:580.22ms
SynchonizedQueue:578.35ms
SynchonizedQueue:578.57ms
Sử dụng đoạn mã sau:
private readonly object _syncObj = new object();
[Test]
public object measure_queue_locking_performance()
{
const int TestIterations = 5;
const int Iterations = (10 * 1000 * 1000);
Action<string, Action> time = (name, test) =>
{
for (int i = 0; i < TestIterations; i++)
{
TimeSpan elapsed = TimeTest(test, Iterations);
Console.WriteLine("{0}:{1:F2}ms", name, elapsed.TotalMilliseconds);
}
};
object itemOut, itemIn = new object();
Queue queue = new Queue();
Queue syncQueue = Queue.Synchronized(queue);
Action test1 =() =>
{
lock (_syncObj) queue.Enqueue(itemIn);
lock (_syncObj) itemOut = queue.Dequeue();
};
Action test2 =() =>
{
syncQueue.Enqueue(itemIn);
itemOut = syncQueue.Dequeue();
};
Console.WriteLine("Iterations:{0:0,0}\r\n", Iterations);
time("Queue+Lock", test1);
time("SynchonizedQueue", test2);
return itemOut;
}
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.GC.Collect")]
private static TimeSpan TimeTest(Action action, int iterations)
{
Action gc =() =>
{
GC.Collect();
GC.WaitForFullGCComplete();
};
Action empty =() => { };
Stopwatch stopwatch1 = Stopwatch.StartNew();
for (int j = 0; j < iterations; j++)
{
empty();
}
TimeSpan loopElapsed = stopwatch1.Elapsed;
gc();
action(); //JIT
action(); //Optimize
Stopwatch stopwatch2 = Stopwatch.StartNew();
for (int j = 0; j < iterations; j++) action();
gc();
TimeSpan testElapsed = stopwatch2.Elapsed;
return (testElapsed - loopElapsed);
}
Chỉ cần lấy ra một khóa bằng cách sử dụng một trong hai phương pháp là điên rồ nhanh chóng. Các hit hiệu suất đến từ bao nhiêu ganh đua có cho các ổ khóa. – serg10