0

这个问题分为两部分。我有一个控制台应用程序,它从多个服务器获取信息并将此信息保存到数据库。为了使这同时执行,我使用了线程。我正在尝试每分钟自动执行一次。

搜索stackoverflow我发现这可以工作:

   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();

}

我怎样才能使这项工作?

4

2 回答 2

2

在您的第一个问题中,使用 .Seconds 只会返回秒值,但您将分钟值定义为 0.5,因此秒将始终为零。

如果要返回需要使用 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. 
于 2016-03-22T13:51:18.433 回答
1

基本上,计时器完全按照它应该做的事情:每 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);

}
于 2016-03-22T14:07:42.127 回答