如何正确地每分钟执行一次线程?
How to execute threads every min correctly?
这个问题分为两部分。
我有一个控制台应用程序,它从多个服务器获取信息并将此信息保存到数据库中。为了使它同时执行,我使用了线程。我试图每分钟自动执行一次。
搜索 Whosebug 我发现这可行:
var timer = new System.Threading.Timer((e) =>
{
var models = ServerHandler.GetServerModels();
foreach (var m in models)
{
ServerHandler.MakeThreads(m);
}
Console.WriteLine("Running...");
Console.WriteLine("Press 'X' to exit or close the window, i : " + i);
i++;
}, null, 0, TimeSpan.FromMinutes(1).Seconds);
然而,这并没有像预期的那样工作,它只执行一次。例如,如果我更改为:
TimeSpan.FromMinutes(0.5).Seconds
或者:
TimeSpan.FromSeconds(30).Seconds
然后就可以了。
我做错了什么?
本题第二部分:
当这真的像我上面展示的那样工作时,会发生其他事情。
该进程连续运行,在 474 个线程后崩溃并表示系统内存不足。
我尝试为此使用线程睡眠,但是当我这样做时,它在运行一次后停止执行。
包括这个如果它可能有帮助:
public static void MakeThreads(ServerModel model)
{
Thread thread = new Thread(() => SaveServerInfo(model));
thread.Start();
//Thread.Sleep(1);
//thread.Join();
}
我怎样才能使这个工作?
在您的第一个问题中,使用 .Seconds 只会 return 秒值,但您将分钟值定义为 .5,因此秒将始终为零。
如果你想return秒你需要使用TotalSeconds
TimeSpan.FromMinutes(0.5).TotalSeconds
并且在您使用的时间跨度中,您应该定义毫秒。所以你得到了大量的线程,因为它每 30 毫秒而不是每 30000 毫秒 运行。
所以使用
TimeSpan.FromMinutes(0.5).TotalMilliseconds
或者我总是觉得更简单的方法
(int)(1000 * 60 * 0.5) // Then you just replace the 0.5 with the number of seconds.
基本上,计时器会准确执行它应该执行的操作:运行 您的代码每 0.5 秒执行一次。 :) 在你的情况下,这是个问题...
(请检查语法错误等,我是用记事本写的)
长解
您的问题似乎是您无法控制线程。以下是我的解决方法:(这个长解决方案或多或少展示了它是如何工作的)
while (true)
{
// we want to run it again in 0.5 seconds.
DateTime start = DateTime.UtcNow.AddSeconds(0.5);
Thread[] threads = new Thread[models.Count];
for (int i=0; i<models.Count; ++i)
{
threads[i] = new Thread((a) => SaveServerInfo((ServerModel)a));
threads[i].Start(models[i]);
}
for (int i=0; i<models.Count; ++i)
{
threads[i].Join();
}
DateTime current = DateTime.UtcNow;
if (current < start)
{
Thread.Sleep(start.Subtract(current));
}
}
简解
但是,这也可能会给您带来问题:您可能会生成太多线程。这可以通过称为线程池的机制来解决。事实证明,有一个简单的方法可以解决这个问题:
static void DoStuff(string s)
{
// change to a value > 0.5 as well to ensure everything works
Thread.Sleep(TimeSpan.FromSeconds(0.1));
Console.WriteLine(s);
}
static void Handle(List<string> models)
{
while (true)
{
// we want to run it again in 0.5 seconds.
DateTime start = DateTime.UtcNow.AddSeconds(0.5);
Parallel.ForEach(models, (a) => DoStuff(a));
DateTime current = DateTime.UtcNow;
if (current < start)
{
Thread.Sleep(start.Subtract(current));
}
}
}
static void Main(string[] args)
{
List<string> models = new List<string>();
for (int i = 0; i < 10; ++i)
{
models.Add(i.ToString());
}
Handle(models);
}
这个问题分为两部分。 我有一个控制台应用程序,它从多个服务器获取信息并将此信息保存到数据库中。为了使它同时执行,我使用了线程。我试图每分钟自动执行一次。
搜索 Whosebug 我发现这可行:
var timer = new System.Threading.Timer((e) =>
{
var models = ServerHandler.GetServerModels();
foreach (var m in models)
{
ServerHandler.MakeThreads(m);
}
Console.WriteLine("Running...");
Console.WriteLine("Press 'X' to exit or close the window, i : " + i);
i++;
}, null, 0, TimeSpan.FromMinutes(1).Seconds);
然而,这并没有像预期的那样工作,它只执行一次。例如,如果我更改为:
TimeSpan.FromMinutes(0.5).Seconds
或者:
TimeSpan.FromSeconds(30).Seconds
然后就可以了。 我做错了什么?
本题第二部分:
当这真的像我上面展示的那样工作时,会发生其他事情。 该进程连续运行,在 474 个线程后崩溃并表示系统内存不足。
我尝试为此使用线程睡眠,但是当我这样做时,它在运行一次后停止执行。
包括这个如果它可能有帮助:
public static void MakeThreads(ServerModel model)
{
Thread thread = new Thread(() => SaveServerInfo(model));
thread.Start();
//Thread.Sleep(1);
//thread.Join();
}
我怎样才能使这个工作?
在您的第一个问题中,使用 .Seconds 只会 return 秒值,但您将分钟值定义为 .5,因此秒将始终为零。
如果你想return秒你需要使用TotalSeconds
TimeSpan.FromMinutes(0.5).TotalSeconds
并且在您使用的时间跨度中,您应该定义毫秒。所以你得到了大量的线程,因为它每 30 毫秒而不是每 30000 毫秒 运行。
所以使用
TimeSpan.FromMinutes(0.5).TotalMilliseconds
或者我总是觉得更简单的方法
(int)(1000 * 60 * 0.5) // Then you just replace the 0.5 with the number of seconds.
基本上,计时器会准确执行它应该执行的操作:运行 您的代码每 0.5 秒执行一次。 :) 在你的情况下,这是个问题...
(请检查语法错误等,我是用记事本写的)
长解
您的问题似乎是您无法控制线程。以下是我的解决方法:(这个长解决方案或多或少展示了它是如何工作的)
while (true)
{
// we want to run it again in 0.5 seconds.
DateTime start = DateTime.UtcNow.AddSeconds(0.5);
Thread[] threads = new Thread[models.Count];
for (int i=0; i<models.Count; ++i)
{
threads[i] = new Thread((a) => SaveServerInfo((ServerModel)a));
threads[i].Start(models[i]);
}
for (int i=0; i<models.Count; ++i)
{
threads[i].Join();
}
DateTime current = DateTime.UtcNow;
if (current < start)
{
Thread.Sleep(start.Subtract(current));
}
}
简解
但是,这也可能会给您带来问题:您可能会生成太多线程。这可以通过称为线程池的机制来解决。事实证明,有一个简单的方法可以解决这个问题:
static void DoStuff(string s)
{
// change to a value > 0.5 as well to ensure everything works
Thread.Sleep(TimeSpan.FromSeconds(0.1));
Console.WriteLine(s);
}
static void Handle(List<string> models)
{
while (true)
{
// we want to run it again in 0.5 seconds.
DateTime start = DateTime.UtcNow.AddSeconds(0.5);
Parallel.ForEach(models, (a) => DoStuff(a));
DateTime current = DateTime.UtcNow;
if (current < start)
{
Thread.Sleep(start.Subtract(current));
}
}
}
static void Main(string[] args)
{
List<string> models = new List<string>();
for (int i = 0; i < 10; ++i)
{
models.Add(i.ToString());
}
Handle(models);
}