Helpex - Trao đổi & giúp đỡ Đăng nhập
34

Tôi muốn gọi luồng ngủ với ít hơn 1 mili giây. Tôi đọc rằng cả thread.SleepWindows-OS đều không hỗ trợ điều đó.

Giải pháp cho điều đó là gì?

Đối với tất cả những ai thắc mắc tại sao tôi cần điều này: Tôi đang làm một bài kiểm tra căng thẳng và muốn biết mô-đun của tôi có thể xử lý bao nhiêu thông báo mỗi giây. Vì vậy, mã của tôi là:

 // Set the relative part of Second hat will be allocated for each message 
 //For example: 5 messages - every message will get 200 miliseconds 
 var quantum = 1000 / numOfMessages;

 for (var i = 0; i < numOfMessages; i++)
 {
      _bus.Publish(new MyMessage());
      if (rate != 0) 
          Thread.Sleep(quantum);
 }

Tôi rất vui khi biết ý kiến ​​của bạn về điều đó.

34 hữu ích 4 bình luận 46k xem chia sẻ
49

Bạn không thể làm điều này. Một cuộc gọi ngủ duy nhất thường sẽ chặn lâu hơn một phần nghìn giây (nó phụ thuộc vào hệ điều hành và hệ thống, nhưng theo kinh nghiệm của tôi, Thread.Sleep(1)có xu hướng chặn trong khoảng từ 12-15ms).

Nói chung, Windows không được thiết kế như một hệ điều hành thời gian thực . Loại kiểm soát này thường không thể đạt được trên các phiên bản Windows bình thường (máy tính để bàn / máy chủ).

Cách gần nhất bạn có thể nhận được thường là quay và ăn các chu kỳ CPU cho đến khi bạn đạt được thời gian chờ mong muốn (được đo bằng bộ đếm hiệu suất cao). Tuy nhiên, điều này khá khủng khiếp - bạn sẽ ngốn toàn bộ CPU và thậm chí sau đó, đôi khi bạn có thể bị hệ điều hành tấn công và "ngủ" hiệu quả lâu hơn 1ms ...

49 hữu ích 5 bình luận chia sẻ
28

Đoạn mã dưới đây chắc chắn sẽ cung cấp một cách chặn chính xác hơn thay vì gọi Thread.Sleep(x);(mặc dù phương pháp này sẽ chặn luồng, không đưa nó vào chế độ ngủ ). Dưới đây, chúng tôi đang sử dụng StopWatchlớp để đo lường thời gian chúng tôi cần tiếp tục lặp lại và chặn luồng gọi.

using System.Diagnostics;

private static void NOP(double durationSeconds)
{
    var durationTicks = Math.Round(durationSeconds * Stopwatch.Frequency);
    var sw = Stopwatch.StartNew();

    while (sw.ElapsedTicks < durationTicks)
    {

    }
}

Ví dụ về cách sử dụng,

private static void Main()
{
    NOP(5); // Wait 5 seconds.

    Console.WriteLine("Hello World!");

    Console.ReadLine();
}
28 hữu ích 5 bình luận chia sẻ
11

Tại sao?
Thông thường, có một số lượng CPU và lõi rất hạn chế trên một máy - bạn chỉ nhận được một số nhỏ nếu các đơn vị thực thi độc lập.

Mặt khác, có một số quy trình và nhiều chủ đề khác. Mỗi luồng yêu cầu một số thời gian xử lý, được chỉ định nội bộ bởi các quy trình lõi của Windows. Thông thường Windows chặn tất cả các luồng và cung cấp một lượng thời gian lõi CPU nhất định cho các luồng cụ thể, sau đó nó chuyển ngữ cảnh sang các luồng khác.

Khi bạn gọi Thread.Sleep, bất kể bạn giết toàn bộ khoảng thời gian mà Windows đã dành cho luồng nhỏ đến mức nào, vì không có lý do gì để chỉ cần đợi nó và ngữ cảnh được chuyển ngay lập tức. Có thể mất vài mili giây khi Windows cung cấp cho luồng của bạn một số CPU vào lần tới.

Sử dụng những gì?
Ngoài ra, bạn có thể quay CPU của mình , quay không phải là điều quá khủng khiếp và có thể rất hữu ích. Ví dụ, nó được sử dụng trong không gian tên System.Collections.Concurrent rất nhiều với các bộ sưu tập không chặn, ví dụ:

SpinWait sw = new SpinWait();
sw.SpinOnce();
11 hữu ích 0 bình luận chia sẻ
8

Hầu hết các lý do chính đáng cho việc sử dụng Thread.Sleep(1)hoặc Thread.Sleep(0)liên quan đến các kỹ thuật đồng bộ hóa luồng khá tiên tiến. Giống như Reed đã nói , bạn sẽ không có được độ phân giải mong muốn nếu sử dụng các kỹ thuật thông thường. Tôi không biết chắc chắn bạn đang cố gắng hoàn thành điều gì, nhưng tôi nghĩ rằng tôi có thể giả định rằng bạn muốn thực hiện một hành động xảy ra trong khoảng thời gian 1 mili giây. Nếu đúng như vậy thì hãy xem bộ hẹn giờ đa phương tiện . Chúng có thể cung cấp độ phân giải xuống 1ms. Rất tiếc, không có API nào được tích hợp trong .NET Framework (mà tôi biết) khai thác vào tính năng Windows này. Nhưng bạn có thể sử dụng lớp interop để gọi trực tiếp vào các API Win32. Thậm chí còn có những ví dụ về việc này trong C #.

8 hữu ích 0 bình luận chia sẻ
4

Ngày xưa, bạn sẽ sử dụng API "QueryPerformanceTimer" của Win32, khi cần độ phân giải dưới mili giây.

Có vẻ như có nhiều thông tin hơn về chủ đề trên Code-Project: http://www.codeproject.com/KB/cs/highperformancetimercshar.aspx

Điều này sẽ không cho phép bạn "Sleep ()" với độ phân giải tương tự như được chỉ ra bởi Reed Copsey.

Chỉnh sửa: Như đã chỉ ra bởi Reed Copsey và Brian Gideon, QueryPerfomanceTimer đã được thay thế bằng Stopwatch.NET

4 hữu ích 4 bình luận chia sẻ
-3

Đối với câu trả lời được chấp nhận của Reed Copsey, còn điều này thì sao?

public void Sleep(double msec)
{
   for (var since = DateTime.Now; (DateTime.Now - since).TotalMilliseconds < msec;)
      Thread.Sleep(TimeSpan.FromTicks(10));
}
-3 hữu ích 0 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ c# .net multithreading , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading