C# 精确替代线程。睡眠
我有一个方法Limit(),它计算某个通道在特定时间内通过的带宽,并使用Thread.Sleep()限制带宽(如果达到带宽限制)。 方法本身会产生适当的(在我看来是结果)但Thread.Sleep不会(由于多线程CPU的使用),因为我有适当的“毫秒Towait”,但之后的速度检查远远不是我通过的限制 有没有办法使限制更精确? 限制器类C# 精确替代线程。睡眠,c#,.net,C#,.net,我有一个方法Limit(),它计算某个通道在特定时间内通过的带宽,并使用Thread.Sleep()限制带宽(如果达到带宽限制)。 方法本身会产生适当的(在我看来是结果)但Thread.Sleep不会(由于多线程CPU的使用),因为我有适当的“毫秒Towait”,但之后的速度检查远远不是我通过的限制 有没有办法使限制更精确? 限制器类 private readonly int m_maxSpeedInKbps; public Limiter(int maxSpeedInKbps)
private readonly int m_maxSpeedInKbps;
public Limiter(int maxSpeedInKbps)
{
m_maxSpeedInKbps = maxSpeedInKbps;
}
public int Limit(DateTime startOfCycleDateTime, long writtenInBytes)
{
if (m_maxSpeedInKbps > 0)
{
double totalMilliseconds = DateTime.Now.Subtract(startOfCycleDateTime).TotalMilliseconds;
int currentSpeedInKbps = (int)((writtenInBytes / totalMilliseconds));
if (currentSpeedInKbps - m_maxSpeedInKbps > 0)
{
double delta = (double)currentSpeedInKbps / m_maxSpeedInKbps;
int millisecondsToWait = (int)((totalMilliseconds * delta) - totalMilliseconds);
if (millisecondsToWait > 0)
{
Thread.Sleep(millisecondsToWait);
return millisecondsToWait;
}
}
}
return 0;
}
在大增量中总是失败的测试类
[TestMethod]
public void ATest()
{
List<File> files = new List<File>();
for (int i = 0; i < 1; i++)
{
files.Add(new File(i + 1, 100));
}
const int maxSpeedInKbps = 1024; // 1MBps
Limiter limiter = new Limiter(maxSpeedInKbps);
DateTime startDateTime = DateTime.Now;
Parallel.ForEach(files, new ParallelOptions {MaxDegreeOfParallelism = 5}, file =>
{
DateTime currentFileStartTime = DateTime.Now;
Thread.Sleep(5);
limiter.Limit(currentFileStartTime, file.Blocks * Block.Size);
});
long roundOfWriteInKB = (files.Sum(i => i.Blocks.Count) * Block.Size) / 1024;
int currentSpeedInKbps = (int) (roundOfWriteInKB/DateTime.Now.Subtract(startDateTime).TotalMilliseconds*1000);
Assert.AreEqual(maxSpeedInKbps, currentSpeedInKbps, string.Format("maxSpeedInKbps {0} currentSpeedInKbps {1}", maxSpeedInKbps, currentSpeedInKbps));
}
[TestMethod]
公共无效测试()
{
列表文件=新列表();
对于(int i=0;i<1;i++)
{
添加(新文件(i+1100));
}
const int maxSpeedInKbps=1024;//1MBps
限制器限制器=新限制器(maxSpeedInKbps);
DateTime startDateTime=DateTime.Now;
ForEach(文件,新的并行选项{MaxDegreeOfParallelism=5},文件=>
{
DateTime currentFileStartTime=DateTime.Now;
睡眠(5);
limiter.Limit(currentFileStartTime,file.Blocks*Block.Size);
});
long-roundOfWriteInKB=(files.Sum(i=>i.Blocks.Count)*Block.Size)/1024;
int currentSpeedInKbps=(int)(roundOfWriteInKB/DateTime.Now.Subtract(startDateTime.TotalMillimes*1000);
AreEqual(maxSpeedInKbps,currentSpeedInKbps,string.Format(“maxSpeedInKbps{0}currentSpeedInKbps{1}”,maxSpeedInKbps,currentSpeedInKbps));
}
我过去经常使用线程。在我发现之前,我经常睡觉。使用waithandles可以挂起线程,当从别处触发waithandle或达到时间阈值时,线程将再次激活。也许可以重新设计您的限制方法,以某种方式使用waithandles,因为在许多情况下,它们确实比Thread.Sleep更精确。
?您可以使用繁忙的等待来相当准确地完成此任务,但我不推荐这样做。你应该使用等待来代替
但是,此方法将相当准确地等待:
void accurateWait(int millisecs)
{
var sw = Stopwatch.StartNew();
if (millisecs >= 100)
Thread.Sleep(millisecs - 50);
while (sw.ElapsedMilliseconds < millisecs)
;
}
void accurateWait(整数毫秒)
{
var sw=Stopwatch.StartNew();
如果(毫秒>=100)
睡眠(毫秒-50);
而(sw.ElapsedMillistes<毫秒)
;
}
但这是一个繁忙的等待,会严重消耗CPU周期。它还可能受到垃圾收集或任务重新调度的影响
以下是测试程序:
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Threading;
namespace Demo
{
class Program
{
void run()
{
for (int i = 1; i < 10; ++i)
test(i);
for (int i = 10; i < 100; i += 5)
test(i);
for (int i = 100; i < 200; i += 10)
test(i);
for (int i = 200; i < 500; i += 20)
test(i);
}
void test(int millisecs)
{
var sw = Stopwatch.StartNew();
accurateWait(millisecs);
Console.WriteLine("Requested wait = " + millisecs + ", actual wait = " + sw.ElapsedMilliseconds);
}
void accurateWait(int millisecs)
{
var sw = Stopwatch.StartNew();
if (millisecs >= 100)
Thread.Sleep(millisecs - 50);
while (sw.ElapsedMilliseconds < millisecs)
;
}
static void Main()
{
new Program().run();
}
}
}
使用系统;
使用系统诊断;
使用System.Collections.Generic;
使用系统线程;
名称空间演示
{
班级计划
{
无效运行()
{
对于(int i=1;i<10;++i)
试验(i);
对于(int i=10;i<100;i+=5)
试验(i);
对于(int i=100;i<200;i+=10)
试验(i);
对于(int i=200;i<500;i+=20)
试验(i);
}
无效测试(整数毫秒)
{
var sw=Stopwatch.StartNew();
准确等待(毫秒);
Console.WriteLine(“请求的等待=“+毫秒+”,实际等待=“+sw.ElapsedMilliseconds”);
}
无效准确等待(整数毫秒)
{
var sw=Stopwatch.StartNew();
如果(毫秒>=100)
睡眠(毫秒-50);
而(sw.ElapsedMillistes<毫秒)
;
}
静态void Main()
{
新程序().run();
}
}
}
你说的“远”到底是什么意思?你说的有多远?你确定线程.Sleep
阻止更多数据进入频道吗?虽然这是真的,你不会得到很多的精度,我不相信这是你的问题。您多久调用一次Limit
?如果您睡眠时间较短,那么实际睡眠时间将不准确-线程时间片为15ms,因此将其加倍或三倍,以获得合理精度的最小增量。但是,你可以用秒表来测量你的实际睡眠时间:实际上在Windows 7和更高版本中,Thread.Sleep()
非常精确-但是DateTime。现在
肯定不是。我明白了,这个问题没有明确说明你发送的是什么。我盲目地假设您正在接收,似乎忽略了参数名为writeninbytes
的事实。无论如何,如果延迟超过300毫秒,我觉得Thread.Sleep
应该足够准确,因为您多次调用Limit
。与块的大小(我相信你说过50KB)相比,总数据大小是多少?您是否愿意发布一个小的可编译示例来说明问题?另外,我支持@MatthewWatson,因为你应该使用秒表而不是日期时间。现在
。你的意思是限制使用WaitHandle,还是用它来包装真正的带宽发送/读取任务,而不是并行。如果现在包装每个任务?当我回答这个问题时,这只是对标题的快速反应“Thread.Sleep的精确替代品”,因为毫无疑问,在某些情况下,waithandles可能比Thread.Sleep更精确。但是,我不熟悉您的带宽限制问题,因此我不确定它们是否适用于这种情况。问题可能是平行的。ForEach()我在其中运行每个IO线程。如果我将并行度限制为1,则结果是精确的。必须是thread.sleep,按您所说停止所有线程,而不是它运行的线程。@eugeneK thread.sleep()真的没有停止所有线程。那太可怕了!