2012-04-13 58 views
7

Tôi mới đến C#; Tôi chủ yếu làm Java.Thực hiện một thời gian chờ trong C#

Tôi muốn thực hiện một cái gì đó dọc theo dòng thời gian chờ:

int now= Time.now(); 
while(true) 
{ 
    tryMethod(); 
    if(now > now+5000) throw new TimeoutException(); 
} 

Làm thế nào tôi có thể thực hiện điều này trong C#? Cảm ơn!

+0

Bạn sẽ muốn nhìn vào [Stopwatch] (http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx) lớp. [Ở đây] (http://stackoverflow.com/a/5019172/95573) là một ví dụ – SwDevMan81

+2

Loại 'tryMethod' làm gì? Trong đoạn mã trên, câu lệnh if của bạn sẽ chỉ đạt được sau khi 'trymethod' đã hoàn tất. – JMK

+2

Điều này có vẻ giống như một cái gì đó bạn có thể muốn thực thi không đồng bộ? – emd

Trả lời

25

Một cách có thể sẽ là

Stopwatch sw = new Stopwatch(); 
sw.Start(); 
while(true) 
{ 
    tryMethod(); 
    if(sw.ElapsedMilliseconds > 5000) throw new TimeoutException(); 
} 

Tuy nhiên bạn hiện không có cách nào để thoát ra khỏi vòng lặp của bạn. Tôi sẽ khuyên bạn nên có tryMethod trả về một boolean và thay đổi nó để

Stopwatch sw = new Stopwatch(); 
sw.Start(); 
while(!tryMethod()) 
{ 
    if(sw.ElapsedMilliseconds > 5000) throw new TimeoutException(); 
} 
+2

Có vấn đề khi nói đến ngày tiết kiệm ánh sáng ban ngày – Servy

+1

@Servy bạn là chính xác, Edited câu trả lời của tôi để sử dụng đồng hồ bấm giờ thay vì DateTime. –

+0

Tôi khá chắc chắn rằng OP muốn có thể thực hiện hoạt động timeout trên tryMethod mặc dù – KingCronus

4

Tôi nghĩ bạn có thể làm điều này với một bộ đếm thời gian và một đại biểu, mã ví dụ của tôi là dưới đây:

using System; 
using System.Timers; 

class Program 
{ 
    public delegate void tm(); 

    static void Main(string[] args) 
    { 
     var t = new tm(tryMethod); 
     var timer = new Timer(); 
     timer.Interval = 5000; 

     timer.Start(); 

     timer.Elapsed += (sender, e) => timer_Elapsed(t); 
     t.BeginInvoke(null, null); 
    } 

    static void timer_Elapsed(tm p) 
    { 
     p.EndInvoke(null); 
     throw new TimeoutException(); 
    } 

    static void tryMethod() 
    { 
     Console.WriteLine("FooBar"); 
    } 
} 

Bạn có tryMethod, bạn sau đó tạo một đại biểu và trỏ đại biểu này tại tryMethod, sau đó bạn bắt đầu đại biểu này Không đồng bộ. Sau đó, bạn có một bộ đếm thời gian, với khoảng thời gian là 5000ms, bạn chuyển ủy nhiệm của bạn vào phương thức đã hết giờ của bạn (hoạt động như đại biểu là loại tham chiếu chứ không phải loại giá trị) và sau khi 5000 giây trôi qua, bạn gọi EndInvoke phương pháp trên đại biểu của bạn.

+0

Tôi nghĩ rằng nó trái ngược với những gì OP muốn - mã này đảm bảo rằng phương pháp không kết thúc cho ít nhất 5000ms, có vẻ như OP muốn chạy một phương pháp liên tục cho tối đa 5000ms. –

+0

Ah xin lỗi, tôi đã nhận được điều này ngược! – JMK

+0

Câu trả lời khác (phiên bản vòng lặp while) dường như không hoạt động với thao tác chặn. Tôi sẽ làm một số thử nghiệm, nhưng chỉ yêu cầu cho bây giờ, phương pháp này sẽ làm việc bộ đếm thời gian để ngăn chặn? – liang

2

Chừng nào tryMethod() không ngăn chặn điều này nên làm những gì bạn muốn:

Không an toàn cho thời gian tiết kiệm ánh sáng ban ngày hoặc thay đổi múi giờ khi điện thoại di động: thời gian

DateTime startTime = DateTime.Now; 

while(true) 
{ 
    tryMethod(); 
    if(DateTime.Now.Subtract(startTime).TotalMilliseconds > 5000) 
     throw new TimeoutException(); 
} 

múi giờ và giờ mùa hè tiết kiệm phiên bản an toàn:

DateTime startTime = DateTime.UtcNow; 

while(true) 
{ 
    tryMethod(); 
    if(DateTime.UtcNow.Subtract(startTime).TotalMilliseconds > 5000) 
     throw new TimeoutException(); 
} 

(. NET 3.5 hoặc cao hơn yêu cầu cho DateTimeOffset)

DateTimeOffset startTime = DateTimeOffset.Now; 

while(true) 
{ 
    tryMethod(); 
    if(DateTimeOffset.Now.Subtract(startTime).TotalMilliseconds > 5000) 
     throw new TimeoutException(); 
} 
+0

là tốt hơn để chuyển đổi DateTime thành Giờ quốc tế để tính các múi giờ khác nhau? Ngoài ra nếu tôi sử dụng UtcNow nó sẽ làm cho bất kỳ sự khác biệt? –

+0

@SimpleFellow Có hai cách để làm cho múi giờ và ánh sáng ban ngày này tiết kiệm thời gian an toàn. Xem câu trả lời được cập nhật. Sử dụng UtcNow tốt hơn chuyển đổi vì chuyển đổi vẫn có thể có vấn đề dựa trên thời điểm chuyển đổi được thực hiện. – JamieSee

0

Một cách khác tôi muốn làm điều đó:

public class TimeoutAction 
    { 
     private Thread ActionThread { get; set; } 
     private Thread TimeoutThread { get; set; } 
     private AutoResetEvent ThreadSynchronizer { get; set; } 
     private bool _success; 
     private bool _timout; 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="waitLimit">in ms</param> 
     /// <param name="action">delegate action</param> 
     public TimeoutAction(int waitLimit, Action action) 
     { 
      ThreadSynchronizer = new AutoResetEvent(false); 
      ActionThread = new Thread(new ThreadStart(delegate 
      { 
       action.Invoke(); 
       if (_timout) return; 
       _timout = true; 
       _success = true; 
       ThreadSynchronizer.Set(); 
      })); 

      TimeoutThread = new Thread(new ThreadStart(delegate 
      { 
       Thread.Sleep(waitLimit); 
       if (_success) return; 
       _timout = true; 
       _success = false; 
       ThreadSynchronizer.Set(); 
      })); 
     } 

     /// <summary> 
     /// If the action takes longer than the wait limit, this will throw a TimeoutException 
     /// </summary> 
     public void Start() 
     { 
      ActionThread.Start(); 
      TimeoutThread.Start(); 

      ThreadSynchronizer.WaitOne(); 

      if (!_success) 
      { 
       throw new TimeoutException(); 
      } 
      ThreadSynchronizer.Close(); 
     } 
    } 
1

Sử dụng Nhiệm vụ cho thời gian chờ tùy chỉnh trên phương pháp async

đây thực hiện của tôi về một lớp tùy chỉnh với một phương pháp để quấn một nhiệm vụ để có một thời gian chờ .

public class TaskWithTimeoutWrapper 
{ 
    protected volatile bool taskFinished = false; 

    public async Task<T> RunWithCustomTimeoutAsync<T>(int millisecondsToTimeout, Func<Task<T>> taskFunc, CancellationTokenSource cancellationTokenSource = null) 
    { 
     this.taskFinished = false; 

     var results = await Task.WhenAll<T>(new List<Task<T>> 
     { 
      this.RunTaskFuncWrappedAsync<T>(taskFunc), 
      this.DelayToTimeoutAsync<T>(millisecondsToTimeout, cancellationTokenSource) 
     }); 

     return results[0]; 
    } 

    public async Task RunWithCustomTimeoutAsync(int millisecondsToTimeout, Func<Task> taskFunc, CancellationTokenSource cancellationTokenSource = null) 
    { 
     this.taskFinished = false; 

     await Task.WhenAll(new List<Task> 
     { 
      this.RunTaskFuncWrappedAsync(taskFunc), 
      this.DelayToTimeoutAsync(millisecondsToTimeout, cancellationTokenSource) 
     }); 
    } 

    protected async Task DelayToTimeoutAsync(int millisecondsToTimeout, CancellationTokenSource cancellationTokenSource) 
    { 
     await Task.Delay(millisecondsToTimeout); 

     this.ActionOnTimeout(cancellationTokenSource); 
    } 

    protected async Task<T> DelayToTimeoutAsync<T>(int millisecondsToTimeout, CancellationTokenSource cancellationTokenSource) 
    { 
     await this.DelayToTimeoutAsync(millisecondsToTimeout, cancellationTokenSource); 

     return default(T); 
    } 

    protected virtual void ActionOnTimeout(CancellationTokenSource cancellationTokenSource) 
    { 
     if (!this.taskFinished) 
     { 
      cancellationTokenSource?.Cancel(); 
      throw new NoInternetException(); 
     } 
    } 

    protected async Task RunTaskFuncWrappedAsync(Func<Task> taskFunc) 
    { 
     await taskFunc.Invoke(); 

     this.taskFinished = true; 
    } 

    protected async Task<T> RunTaskFuncWrappedAsync<T>(Func<Task<T>> taskFunc) 
    { 
     var result = await taskFunc.Invoke(); 

     this.taskFinished = true; 

     return result; 
    } 
} 

Sau đó, bạn có thể gọi nó như thế này:

await new TaskWithTimeoutWrapper().RunWithCustomTimeoutAsync(10000,() => this.MyTask()); 

hoặc

var myResult = await new TaskWithTimeoutWrapper().RunWithCustomTimeoutAsync(10000,() => this.MyTaskThatReturnsMyResult()); 

Và bạn có thể thêm một mã thông báo hủy bỏ nếu bạn muốn hủy bỏ nhiệm vụ async chạy nếu nó được để hết giờ.

Hy vọng nó giúp

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