2012-03-30 69 views

Trả lời

35

Có rất nhiều cách để làm điều đó:

  • Phương pháp một: hình sự khủng khiếp: Bận-wait:

    DateTime timeToStartUpAgain = whatever;

    while(DateTime.Now < timeToStartUpAgain) {}

Đây là một điều khủng khiếp để làm; hệ điều hành sẽ cho rằng bạn đang làm công việc hữu ích và sẽ chỉ định một CPU để không làm gì khác ngoài việc quay về điều này. Không bao giờ làm điều này trừ khi bạn biết rằng spin sẽ chỉ trong vài micro giây. Về cơ bản khi bạn làm điều này bạn đã thuê một người nào đó để xem đồng hồ cho bạn; đó không phải là kinh tế.

  • Cách hai: Rất đáng sợ: Ngủ chỉ.

Ngủ một sợi cũng là một điều kinh khủng, nhưng ít kinh khủng hơn là làm nóng CPU. Ngủ một thread cho hệ điều hành "thread này của ứng dụng này nên ngừng đáp ứng với các sự kiện trong một thời gian và không phải làm gì". Điều này tốt hơn việc thuê một người nào đó để xem đồng hồ cho bạn; bây giờ bạn đã thuê một người nào đó để ngủ cho bạn.

  • Cách ba: Chia công việc thành các tác vụ nhỏ hơn. Tạo bộ hẹn giờ. Khi bạn muốn có một sự chậm trễ, thay vì làm nhiệm vụ tiếp theo, hãy tạo một bộ hẹn giờ. Khi bộ đếm thời gian kích hoạt sự kiện đánh dấu của nó, hãy chọn danh sách nhiệm vụ bạn đã dừng lại.

Điều này giúp sử dụng hiệu quả tài nguyên; bây giờ bạn đang thuê một người nào đó để nấu trứng và trong khi những quả trứng đang nấu ăn, họ có thể làm bánh mì nướng.

Tuy nhiên, thật khó để viết chương trình của bạn để nó chia nhỏ công việc thành các tác vụ nhỏ.

  • Phương pháp bốn: sử dụng hỗ trợ của C# 5 cho lập trình không đồng bộ; đang chờ nhiệm vụ Delay và để trình biên dịch C# chăm sóc tái cơ cấu chương trình của bạn để làm cho nó hiệu quả.

Mặt trái của khóa học là tất nhiên C# 5 hiện chỉ có bản beta.

LƯU Ý: Kể từ khi Visual Studio 2012 C# 5 đang được sử dụng. Nếu bạn đang sử dụng VS 2012 hoặc chương trình không đồng bộ sau này có sẵn cho bạn.

7

Sử dụng Thread.Sleep (từ System.Threading):

for(int i = 0 ; i<64;i++) 
{ 
    if(i % 8 == 0) 
     Thread.Sleep(1000); 
} 
+0

+1 cho cả hai câu trả lời, cũng sẽ chặn chuỗi giao diện người dùng nếu sử dụng sai. –

+2

Điều đó sẽ ngủ sau lần lặp đầu tiên. – user7116

12

Nếu bạn muốn có một giấc ngủ sau mỗi 8 lần lặp lại, cố gắng này:

for (int i = 0; i < 64; i++) 
{ 
    //... 
    if (i % 8 == 7) 
     Thread.Sleep(1000); //ms 
} 
2

Bạn cũng có thể muốn chỉ cần nhìn vào cách sử dụng một Timer thay vì tạm dừng luồng hiện tại trong một vòng lặp.

Nó sẽ cho phép bạn thực hiện một số khối mã (nhiều lần hoặc không) sau một khoảng thời gian. Nếu không có nhiều ngữ cảnh thì sẽ khó có thể nói chắc chắn nếu đó là điều tốt nhất trong tình huống của bạn hay cách bạn sẽ thay đổi giải pháp của bạn cho phù hợp.

1

Đây là triển khai mà tôi đã đưa ra. Nó là chung chung, vì vậy bạn có thể dễ dàng tái sử dụng nó cho trường hợp sử dụng của bạn. (Nó gắn với những gì @Servy gợi ý)

public static async Task ForEachWithDelay<T>(this ICollection<T> items, Func<T, Task> action, double interval) 
{ 
    using (var timer = new System.Timers.Timer(interval)) 
    { 
     var task = new Task(() => { }); 
     int remaining = items.Count; 
     var queue = new ConcurrentQueue<T>(items); 

     timer.Elapsed += async (sender, args) => 
     { 
      T item; 
      if (queue.TryDequeue(out item)) 
      { 
       try 
       { 
        await action(item); 
       } 
       finally 
       { 
        // Complete task. 
        remaining -= 1; 

        if (remaining == 0) 
        { 
         // No more items to process. Complete task. 
         task.Start(); 
        } 
       } 
      } 
     }; 

     timer.Start(); 

     await task; 
    } 
} 

Và sau đó sử dụng nó như vậy:

var numbers = Enumerable.Range(1, 10).ToList(); 
var interval = 1000; // 1000 ms delay 
numbers.ForEachWithDelay(i => Task.Run(() => Console.WriteLine(i + " @ " + DateTime.Now)), interval); 

mà in này:

1 @ 2/2/2016 9:45:37 AM 
2 @ 2/2/2016 9:45:38 AM 
3 @ 2/2/2016 9:45:39 AM 
4 @ 2/2/2016 9:45:40 AM 
5 @ 2/2/2016 9:45:41 AM 
6 @ 2/2/2016 9:45:42 AM 
7 @ 2/2/2016 9:45:43 AM 
8 @ 2/2/2016 9:45:44 AM 
9 @ 2/2/2016 9:45:45 AM 
10 @ 2/2/2016 9:45:46 AM 
0

Hãy thử phiên bản này đơn giản hơn mà không phụ thuộc vào async hay đang chờ hoặc TPL.

  1. Tạo ra 50 cuộc gọi phương pháp,
  2. ngủ trong 20 giây,
  3. kiểm tra nó 20 hoặc x mục được hoàn thành.
  4. nếu không ngủ một lần nữa trong 20 giây
  5. nếu có sơ yếu lý lịch vòng

Mã đây

foreach (var item in collection) 
      { 
       if (cnt < 50) 
       { 
        cnt++; 
        DoWork(item); 
       } 
       else 
       { 
        bool stayinLoop = true; 
        while (stayinLoop) 
        { 
         Thread.Sleep(20000); 
         if (cnt < 30) 
         { 
          stayinLoop = false; 
          DoWork(item); 
         } 
        } 
       } 
      } 

Làm việc trong một thread riêng biệt, vì vậy giấc ngủ mà không chặn bạn, có thể là nhân viên nền, Bắt đầu, Kết thúc phương thức yêu cầu web hoặc tùy chọn tác vụ không đồng bộ hoặc Task.Run()

function DoWork() 
//Do work in a sep thread. 
cnt--; 
) 
Các vấn đề liên quan