2011-09-14 35 views
9

Tôi gặp sự cố. Tôi đang viết một điểm chuẩn và tôi có một chức năng hơn là được thực hiện trong 2 giây hoặc sau ~ 5 phút (tùy thuộc vào dữ liệu đầu vào). Và tôi muốn dừng chức năng đó nếu nó được thực hiện trong hơn 3 giây ...Làm thế nào để hạn chế thời gian thực hiện của một hàm trong c sắc nét?

Tôi có thể làm như thế nào?

Cảm ơn rất nhiều!

+0

có thể trùng lặp http://stackoverflow.com/questions/5025509/how-to-estimate-method-execution-time – Reniuz

+0

Có, trùng lặp, điểm chuẩn kết thúc theo cùng cách với bất kỳ chuỗi nào khác dừng lại. –

Trả lời

3

Cách tốt nhất sẽ là chức năng của bạn có thể kiểm tra thời gian thực hiện của nó thường xuyên đủ để quyết định để ngăn chặn nó phải mất quá nhiều thời gian.

Nếu trường hợp này không đúng, hãy chạy hàm trong một chuỗi riêng biệt. Trong chủ đề chính của bạn, bắt đầu hẹn giờ 3 giây. Khi bộ đếm thời gian trôi qua, hãy hủy chuỗi riêng biệt bằng cách sử dụng Thread.Abort() (tất nhiên trừ khi chức năng đã kết thúc). Xem mã mẫu và các điều khoản sử dụng trong tài liệu hàm.

+0

Đó là thực sự dễ dàng hơn nhiều. Nếu bạn thực sự cần phải giết các chủ đề một cách không thân thiện, sử dụng một sợi chỉ là cách tôi biết. – gjvdkamp

+0

vâng, đây có vẻ là phương pháp đơn giản nhất và dễ hiểu nhất. Cảm ơn – Novellizator

0

Chạy chức năng này trong chủ đề và tiêu diệt nó sau 3 giây hoặc kiểm tra thời gian đã trôi qua bên trong chức năng này (tôi nghĩ rằng đó là vòng lặp ở đó).

+1

Điều này sẽ chỉ biến chức năng thành một vòng kiểm tra, để lại nó không có chức năng khác. Giết chủ đề cũng không được đảm bảo. Nó sẽ không bị giết cho đến khi nó thoát khỏi chức năng. –

0

Vì khung công tác C# và .net không phải là môi trường thời gian thực nên bạn không thể đảm bảo ngay cả 3 giây. Ngay cả khi bạn đã gần đến mức đó, bạn vẫn phải gọi số

if(timeSpan > TimeSpan.FromSeconds(3) then goto endindentifier; trước mọi cuộc gọi khác trong phương thức.

Tất cả điều này chỉ là sai nên không, không có cách nào đáng tin cậy để làm điều đó từ những gì tôi biết.

Mặc dù bạn có thể thử giải pháp này

https://web.archive.org/web/20140222210133/http://kossovsky.net/index.php/2009/07/csharp-how-to-limit-method-execution-time

nhưng tôi chỉ sẽ không làm những việc như vậy trong ứng dụng .net.

+0

Xin chào, CPC Cửa sổ Microsoft cũng không phải là hệ điều hành thời gian thực –

+0

Bạn có thể sử dụng các cuộc gọi lại với các bộ đếm hiệu suất hi trên các cửa sổ bằng Win32 và interop, sau đó –

+0

@Artur, lý do tôi nói về .net và không cửa sổ, là vì C# cũng có thể được thực thi Các hệ điều hành dựa trên Unix thông qua Mono và tôi không chắc liệu tất cả các hệ điều hành hỗ trợ Mono đó không phải là thời gian thực hay không. Có thể lắp ráp một hệ thống thời gian thực, nhưng Mono nhiều khả năng sẽ không bao giờ là thời gian thực, cũng như .Net, đơn giản vì hiện tại không cần thiết. –

0

Sử dụng một callbacks OS với một hiệu suất truy cập hi, sau đó giết chủ đề của bạn, nếu tồn tại

+0

Cách API giết chết một chuỗi được quản lý có đảm bảo việc xóa luồng ngay lập tức (trên một lần xử lý tiếp theo) không? –

3

Bạn có thể dùng nĩa/join mô hình, trong thư viện song song công tác này được thực hiện với Task.WaitAll()

using System.Threading.Tasks; 

void CutoffAfterThreeSeconds() { 

    // start function on seperate thread 
    CancellationTokenSource cts = new CancellationTokenSource(); 
    Task loop = Task.Factory.StartNew(() => Loop(cts.Token)); 

    // wait for max 3 seconds 
    if(Task.WaitAll(new Task[]{loop}, 3000)){ 
     // Loop finished withion 3 seconds 
    } else { 
     // it did not finish within 3 seconds 
     cts.Cancel();   
    }   
} 

// this one takes forever 
void Loop() { 
    while (!ct.IsCancellationRequested) { 
     // your loop goes here 
    } 
    Console.WriteLine("Got Cancelled"); 
} 

này sẽ bắt đầu nhiệm vụ khác trên một sợi riêng biệt, và sau đó chờ cho 3000 mili giây cho nó hoàn thành. Nếu nó đã kết thúc trong thời gian chờ, nó trở lại đúng, sai khác để bạn có thể sử dụng nó để quyết định làm gì tiếp theo.

Bạn có thể sử dụng CancellationToken để giao tiếp với chủ đề khác mà kết quả không còn cần thiết để nó có thể dừng một cách duyên dáng.

Kính trọng Gert-Jan

+0

ok, nó có vẻ dễ dàng và có thể sử dụng :) Một câu hỏi cuối cùng: làm thế nào tôi có thể hủy bỏ Loop chạy() một cách nào đó? – Novellizator

+0

Loại phụ thuộc vào những gì bạn đang làm ở đó ... là một số loại vòng lặp (trong đó bạn có thể xác định mã thông báo hủy?) Hoặc bạn gọi vào một số mã khác mà bạn không thể thay đổi? Điều này quyết định chiến lược. Nếu hoạt động runnnig dài là mã của bạn, thì bạn cehck CancellationToken.Nếu đó là một số mã khác thì bạn có thể cần phải ít thân thiện hơn và thực sự giết các chủ đề. Điều này có thể dẫn đến tình trạng không phù hợp. Tôi sẽ cập nhật ví dụ với mã thông báo hủy. – gjvdkamp

+0

ok cập nhật ví dụ – gjvdkamp

44

Vâng ..., Tôi đã có cùng một câu hỏi, và sau khi đọc tất cả các câu trả lời ở đây và các blog gọi, tôi giải quyết cho điều này,

nó cho phép tôi thực hiện bất kỳ khối mã với thời gian giới hạn, Khai báo phương pháp wrapper

public static bool ExecuteWithTimeLimit(TimeSpan timeSpan, Action codeBlock) 
    { 
     try 
     { 
      Task task = Task.Factory.StartNew(() => codeBlock()); 
      task.Wait(timeSpan); 
      return task.IsCompleted; 
     } 
     catch (AggregateException ae) 
     { 
      throw ae.InnerExceptions[0]; 
     } 
    } 

Và sử dụng để quấn bất kỳ khối mã như

// code here 

    bool Completed = ExecuteWithTimeLimit(TimeSpan.FromMilliseconds(1000),() => 
    { 
     // 
     // Write your time bounded code here 
     // 
    }); 

    //More code 
+4

Từ sự hiểu biết của tôi, điều này sẽ không dừng mã hành độngBlock nếu nó vẫn chạy sau timeSpan. Trong kịch bản điểm chuẩn của bạn sẽ thay đổi đáng kể kết quả của bạn nếu bạn có nhiều mã chạy song song. –

+0

Tôi nghĩ bạn cần viết 'Task task = new Task (codeBlock); task.Wait (timeSpan); task.Start(); return task.IsCompleted; 'bởi vì với mã của bạn, bạn đang bắt đầu phương thức và yêu cầu nó đợi x lần. Nhưng thực sự chỉ cần chỉ định một nhiệm vụ chờ đợi và bắt đầu nhiệm vụ là một cách tiếp cận tốt hơn. –

2

cách tốt nhất này trong C# để ngăn chặn chức năng ở giữa là từ khóa return trong chức năng, nhưng làm thế nào để tôi biết khi nào nên sử dụng return từ khóa để dừng chức năng ở giữa, sau khi nó kéo dài ít nhất 3 giây? Lớp học Stopwatch từ System.Diagnostics là câu trả lời. Hàm phức tạp này kéo dài từ 2 giây đến 5 phút (tùy thuộc vào dữ liệu đầu vào) hợp lý sử dụng nhiều vòng lặp, và thậm chí có thể đệ quy, vì vậy giải pháp của tôi cho bạn là ở mã đầu tiên của hàm đó, tạo một thể hiện của Stopwatch sử dụng System.Diagnostics với từ khóa new, bắt đầu nó bằng cách gọi Start() chức năng của lớp Stopwatch, và cho mỗi vòng lặp và vòng lặp, ngay từ đầu, thêm đoạn mã sau:

if (stopwatch.ElapsedMilliseconds >= 3000) { 
    stopwatch.Stop(); 
    // or 
    stopwatch.Reset(); 
    return; 
} 

(tip: bạn có thể gõ nó với bàn tay một lần, sao chép nó Ctrl + C, và sau đó chỉ cần dán nó Ctrl + V). Nếu chức năng đó sử dụng đệ quy, để tiết kiệm bộ nhớ, hãy tạo ra thể hiện toàn cục Đồng hồ bấm giờ thay vì tạo nó như thể hiện cục bộ lúc đầu, và khởi động nó nếu nó không chạy ở đầu mã. Bạn có thể biết rằng với số IsRunning của lớp Đồng hồ bấm giờ. Sau đó yêu cầu thời gian trôi qua dài hơn 3 giây và nếu có (true) dừng hoặc đặt lại Đồng hồ bấm giờ và sử dụng từ khóa return để dừng vòng lặp đệ quy, khởi động rất tốt, nếu chức năng của bạn kéo dài trong thời gian dài do đệ quy chủ yếu nhiều hơn các vòng lặp. Đó là nó. Như bạn có thể thấy, nó rất đơn giản, và tôi đã thử nghiệm giải pháp này, và kết quả cho thấy nó hoạt động! Hãy tự mình thử!

+0

Câu trả lời hay nhất là đơn giản và nhanh chóng. Bạn có nội dung tốt nhưng bạn nên xem xét sửa đổi. – WolfLink

Các vấn đề liên quan