System.Timers.Timer vs System.Threading.Timer


565

Tôi đã kiểm tra một số bộ tính giờ có thể gần đây System.Threading.TimerSystem.Timers.Timerlà những bộ có vẻ cần thiết đối với tôi (vì chúng hỗ trợ tổng hợp luồng).

Tôi đang làm một trò chơi, và tôi dự định sử dụng tất cả các loại sự kiện, với các khoảng thời gian khác nhau, v.v.

Cái nào sẽ là tốt nhất?

Câu trả lời:


363

Bài viết này cung cấp một lời giải thích khá toàn diện:

" So sánh các lớp Timer trong Thư viện lớp .NET Framework " - cũng có sẵn dưới dạng tệp .chm

Sự khác biệt cụ thể dường như System.Timers.Timerlà hướng đến các ứng dụng đa luồng và do đó an toàn cho luồng thông qua thuộc tính của nó SynchronizationObject, trong khi đó, System.Threading.Timertrớ trêu là không an toàn ngoài luồng.

Tôi không tin rằng có một sự khác biệt giữa hai điều này vì nó liên quan đến khoảng thời gian nhỏ của bạn có thể.


69
Tôi nghĩ đoạn trích này là khai sáng: "Không giống như System.Windows.Forms.Timer, lớp System.Timers.Timer, theo mặc định, sẽ gọi trình xử lý sự kiện hẹn giờ của bạn trên một luồng công nhân có được từ nhóm luồng ngôn ngữ chung (CLR) . [...] Lớp System.Timers.Timer cung cấp một cách dễ dàng để giải quyết vấn đề nan giải này. Nó phơi bày một thuộc tính SyncizingObject công khai. Đặt thuộc tính này thành một thể hiện của Biểu mẫu Windows (hoặc điều khiển trên Biểu mẫu Windows) sẽ đảm bảo rằng mã trong trình xử lý sự kiện đã trôi qua của bạn chạy trên cùng một luồng mà Đồng bộ hóa được khởi tạo. "
mico

7
Theo Chủ đề phần an toàn trong Threading.Timer's bài viết MSDN , nó là hoàn toàn thread-safe ...
Pieter

62
System.Threading.Timerlà "trớ trêu thay" không an toàn cho luồng như System.Threading.Threadvà các luồng thu được qua nhóm. Chỉ vì các lớp này không nắm tay bạn và quản lý việc sử dụng locktừ khóa không có nghĩa là các lớp này không an toàn. Bạn cũng có thể nói System.Threading.Threadlà không an toàn, bởi vì nó chính xác là đúng.
Kirk Woll

8
Ngoài ra, khoảng thời gian System.Timer.Timer chỉ có thể là Int32 System.Threading. Khoảng thời gian có thể lên tới Int64
Brent

11
Thật không may là câu trả lời sai lệch (tốt nhất) này được chấp nhận và rất được bình chọn. Tuyên bố vật chất duy nhất trong câu trả lời đơn giản là sai. Điều SynchronizingObjectnày không làm cho đối tượng hẹn giờ tự xử lý an toàn. Nó chỉ đảm bảo rằng mã của bạn để xử lý sự kiện hẹn giờ được gọi trong một luồng cụ thể (nếu bạn đặt thuộc tính đó một cách thích hợp). Bản thân đối tượng hẹn giờ vẫn không được đảm bảo an toàn cho luồng, như được nêu rõ trong tài liệu. Mặt khác, System.Threading.Timerđối tượng được ghi lại cụ thể là an toàn cho luồng.
Peter Duniho

169

System.Threading.Timerlà một bộ đếm thời gian đơn giản. Nó gọi bạn trở lại trên một chủ đề nhóm chủ đề (từ nhóm công nhân).

System.Timers.Timerlà một System.ComponentModel.Componentkết thúc tốt đẹp System.Threading.Timervà cung cấp một số tính năng bổ sung được sử dụng để gửi đi trên một luồng cụ thể.

System.Windows.Forms.Timerthay vào đó kết thúc một thông điệp gốc - chỉ HWND và sử dụng Bộ đếm thời gian cửa sổ để nâng cao các sự kiện trong vòng lặp thông báo HWND đó.

Nếu ứng dụng của bạn không có giao diện người dùng và bạn muốn có bộ đếm thời gian .Net nhẹ và có mục đích chung nhất có thể, (vì bạn rất vui khi tìm ra luồng / gửi của riêng bạn) thì System.Threading.Timercũng tốt như trong khung.

Tôi không hoàn toàn rõ ràng vấn đề được cho là 'không an toàn' System.Threading.Timerlà gì. Có lẽ nó cũng giống như được hỏi trong câu hỏi này: An toàn chủ đề của System.Timers.Timer vs System.Threading.Timer , hoặc có lẽ mọi người chỉ có nghĩa là:

  1. thật dễ dàng để viết điều kiện cuộc đua khi bạn đang sử dụng bộ tính giờ. Ví dụ: xem câu hỏi này: An toàn luồng của Timer (System.Threading)

  2. nhập lại các thông báo hẹn giờ, trong đó sự kiện hẹn giờ của bạn có thể kích hoạt và gọi lại cho bạn lần thứ hai trước khi bạn xử lý xong sự kiện đầu tiên . Ví dụ: xem câu hỏi này: Thực thi an toàn luồng bằng System.Threading.Timer và Monitor


Đúng là System.Timers.Timersử dụng System.Threading.Timernội bộ. Xem mã nguồn .
stomy

120

Trong cuốn sách " CLR Via C # ", Jeff Ritcher không khuyến khích sử dụng System.Timers.Timer, bộ đếm thời gian này có nguồn gốc từ System.ComponentModel.Component, cho phép nó được sử dụng trong bề mặt thiết kế của Visual Studio. Vì vậy, nó sẽ chỉ hữu ích nếu bạn muốn có một bộ đếm thời gian trên bề mặt thiết kế.

Anh ấy thích sử dụng System.Threading.Timercho các tác vụ nền trên một chuỗi chủ đề.


36
Nó có thể được sử dụng trong một bề mặt thiết kế - điều đó không có nghĩa là nó phải như vậy và không có tác động bất lợi nào từ việc không làm như vậy. Đọc bài viết trong câu trả lời trước cho câu hỏi này, Timers.Timer có vẻ thích hợp hơn với Threading.Timer.
Stephen Drew

6
Vâng, những gì là tốt hơn phụ thuộc vào bối cảnh, phải không? Theo tôi hiểu, System.Threading.Timer thực hiện cuộc gọi lại truyền qua trên một luồng công nhân mới từ ThreadPool. Mà, tôi giả sử cũng là lý do tại sao nó không nhất thiết phải an toàn cho chuỗi. Kinda có ý nghĩa. Vì vậy, về mặt lý thuyết, bạn sẽ không phải lo lắng về sự càu nhàu của việc quay sợi chỉ công nhân của riêng bạn, vì bộ đếm thời gian này sẽ làm điều đó cho bạn. Kinda có vẻ vô lý hữu ích.
Finster

6
Sử dụng System.Threading.Timergiống như sử dụng nhóm luồng hoặc tạo luồng của riêng bạn. Tất nhiên các lớp này không xử lý đồng bộ hóa cho bạn - đó là công việc của bạn! Cả luồng xử lý chuỗi, luồng của riêng bạn, cũng không phải cuộc gọi lại hẹn giờ sẽ xử lý khóa - trên đối tượng nào và trong trường hợp nào và trong trường hợp nào bạn cần khóa đòi hỏi sự phán đoán tốt và phiên bản luồng của bộ hẹn giờ mang lại cho bạn sự linh hoạt nhất và độ hạt.
Kirk Woll

2
-1 câu trả lời này là chủ quan hoặc có ý kiến ​​ngay từ đầu và không cung cấp thông tin cụ thể về lý do System.Threading.Timer được Jeff Ritcher ưa thích
Brian Ogden

42

Thông tin từ Microsoft về điều này (xem Nhận xét về MSDN ):

  • System.Timers.Timer , thực hiện một sự kiện và thực thi mã trong một hoặc nhiều sự kiện chìm trong khoảng thời gian đều đặn. Lớp này được thiết kế để sử dụng như một thành phần dựa trên máy chủ hoặc dịch vụ trong môi trường đa luồng; Nó không có giao diện người dùng và không hiển thị trong thời gian chạy.
  • System.Threading.Timer , thực thi một phương thức gọi lại duy nhất trên một chuỗi nhóm luồng trong khoảng thời gian đều đặn. Phương thức gọi lại được xác định khi bộ định thời được khởi tạo và không thể thay đổi. Giống như lớp System.Timers.Timer, lớp này được thiết kế để sử dụng như một thành phần dựa trên máy chủ hoặc dịch vụ trong môi trường đa luồng; Nó không có giao diện người dùng và không hiển thị trong thời gian chạy.
  • System.Windows.Forms.Timer (chỉ .NET Framework), một thành phần Windows Forms thực hiện một sự kiện và thực thi mã trong một hoặc nhiều sự kiện chìm trong các khoảng thời gian đều đặn. Thành phần này không có giao diện người dùng và được thiết kế để sử dụng trong môi trường đơn luồng; nó thực thi trên luồng UI.
  • System.Web.UI.Timer (chỉ .NET Framework), một thành phần ASP.NET thực hiện các postback trang web không đồng bộ hoặc đồng bộ tại một khoảng thời gian thông thường.

Thật thú vị khi đề cập đến việc System.Timers.Timerkhông dùng .NET Core 1.0, nhưng đã được triển khai lại trong .NET Core 2.0 (/ .NET Standard 2.0). Mục tiêu với .NET Standard 2.0 là việc chuyển đổi từ .NET Framework có thể dễ dàng nhất có thể là lý do khiến nó quay trở lại.

Khi nó không được dùng nữa, Trình phân tích tính di động .NET Visual Studio Bổ trợ nên sử dụng System.Threading.Timerthay thế.

Có vẻ như Microsoft ủng hộ System.Threading.Timertrước đây System.Timers.Timer.

EDIT NOTE 2018-11-15: Tôi sẵn sàng thay đổi câu trả lời của mình vì thông tin cũ về .NET Core 1.0 không còn hiệu lực nữa.



@Taegost, việc sử dụng nó cũng bị giới hạn - xem MSDN msdn.microsoft.com/en-us/library/... và đọc những nhận xét về nền tảng sẵn có.
Astrowalker

@astrowalker - Cảm ơn vì điều đó, tại thời điểm tôi đưa ra nhận xét, câu trả lời này gần như không có chi tiết. Vì bây giờ nó có chi tiết tôi đang tìm hiểu, tôi đã xóa bình luận của tôi.
Taegost

1
System.Timers.Timer hiện được hỗ trợ trong .NET Standard 2.0 và .NET Core 2.0 trở lên. docs.microsoft.com/en-us/dotnet/api/system.timers.timer (cuộn đến cuối bài viết)
Lee Grissom


39

Một sự khác biệt quan trọng không được đề cập ở trên có thể khiến bạn hiểu ra là System.Timers.Timerâm thầm nuốt ngoại lệ, trong khi System.Threading.Timerkhông.

Ví dụ:

var timer = new System.Timers.Timer { AutoReset = false };
timer.Elapsed += (sender, args) =>
{
    var z = 0;
    var i = 1 / z;
};
timer.Start();

đấu với

var timer = new System.Threading.Timer(x =>
{
    var z = 0;
    var i = 1 / z;
}, null, 0, Timeout.Infinite);

1
Gần đây tôi đã gặp vấn đề này với Timers.Timer và nó đã rất đau đớn ... Có ý tưởng nào tôi có thể viết lại bằng Threading.Timer không? stackoverflow.com/questions/41618324/
Mạnh

7
Có một sản phẩm khai thác trống trong mã nguồn. Xem mã nguồn System.Timers.Timer tại đây
stomy

Omgsh tại sao các lập trình viên MS không thể làm những điều tương tự thực sự giống nhau?
xmedeko

2
Ví dụ không giải thích làm thế nào một người nuốt ngoại lệ và người kia thì không. Ai đó có thể xin vui lòng điền vào các chi tiết?
sean

24

Tôi tìm thấy một so sánh ngắn từ MSDN

Thư viện lớp .NET Framework bao gồm bốn lớp có tên Timer, mỗi lớp cung cấp các chức năng khác nhau:

System.Timers.Timer, trong đó thực hiện một sự kiện và thực thi mã trong một hoặc nhiều sự kiện chìm trong khoảng thời gian đều đặn. Lớp này được thiết kế để sử dụng như một thành phần dựa trên máy chủ hoặc dịch vụ trong môi trường đa luồng; Nó không có giao diện người dùng và không hiển thị trong thời gian chạy.

System.Threading.Timer, thực thi một phương thức gọi lại duy nhất trên một chuỗi nhóm luồng trong khoảng thời gian đều đặn. Phương thức gọi lại được xác định khi bộ định thời được khởi tạo và không thể thay đổi. Giống như lớp System.Timers.Timer, lớp này được thiết kế để sử dụng như một thành phần dựa trên máy chủ hoặc dịch vụ trong môi trường đa luồng; Nó không có giao diện người dùng và không hiển thị trong thời gian chạy.

System.Windows.Forms.Timer, một thành phần Windows Forms thực hiện một sự kiện và thực thi mã trong một hoặc nhiều sự kiện chìm trong các khoảng thời gian đều đặn. Thành phần này không có giao diện người dùng và được thiết kế để sử dụng trong môi trường đơn luồng.

System.Web.UI.Timer, một thành phần ASP.NET thực hiện các postback trang web không đồng bộ hoặc đồng bộ tại một khoảng thời gian đều đặn.


1

Hai lớp có chức năng tương đương, ngoại trừ việc System.Timers.Timercó một tùy chọn để gọi tất cả các callbacks timer hết hạn của mình thông qua ISynchronizeInvoke bằng cách thiết lập SynchronizingObject . Mặt khác, cả hai bộ định thời gọi các cuộc gọi lại hết hạn trên các luồng nhóm luồng.

Khi bạn kéo một System.Timers.Timerbề mặt thiết kế Windows Forms, Visual Studio sẽ đặt SyncizingObject cho đối tượng biểu mẫu, điều này khiến cho tất cả các cuộc gọi lại hết hạn được gọi trên luồng UI.


1

Từ MSDN: System.Threading.Timerlà một bộ đếm thời gian đơn giản, nhẹ, sử dụng các phương thức gọi lại và được phục vụ bởi các luồng nhóm luồng. Nó không được khuyến khích sử dụng với Windows Forms, vì các cuộc gọi lại của nó không xảy ra trên luồng giao diện người dùng. System.Windows.Forms.Timerlà một lựa chọn tốt hơn để sử dụng với Windows Forms. Đối với chức năng hẹn giờ dựa trên máy chủ, bạn có thể cân nhắc sử dụng System.Timers.Timer, điều này làm tăng các sự kiện và có các tính năng bổ sung.

Nguồn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.