C# 关于System.Threading.Timer和Parallel的几个问题

C# 关于System.Threading.Timer和Parallel的几个问题,c#,.net,multithreading,C#,.net,Multithreading,我想每隔x秒启动一些函数。但是我不想等到任何函数完成后再启动它。假设我将计时器设置为5秒,然后启动functionX(),5秒后functionX()未完成=>我想在新线程中再次启动functionX()。我还希望一组函数同时启动 这就是为什么我认为我必须使用System.Threading.Timer和Parallel让我们写一个简短的例子,我认为应该是这样的: class Program { private static System.Threading.Timer

我想每隔x秒启动一些函数。但是我不想等到任何函数完成后再启动它。假设我将计时器设置为5秒,然后启动
functionX()
,5秒后
functionX()
未完成=>我想在新线程中再次启动
functionX()
。我还希望一组函数同时启动

这就是为什么我认为我必须使用
System.Threading.Timer
Parallel
让我们写一个简短的例子,我认为应该是这样的:

class Program
    {
        private static System.Threading.Timer timer;
        private static int interval = 2000;

        static void Main(string[] args)
        {
            Console.WriteLine("go");
            Run();
            Console.WriteLine("end");
            Console.ReadKey();
        }

        private static void Run()
        {
            timer = new System.Threading.Timer(TimerCallback, null, 0, interval);
        }

        private static void TimerCallback(Object o) {
            Parallel.Invoke(() => FunctionA(), () => FunctionB(), () => FunctionC());
        }

        private static void FunctionA()
        {
            Console.WriteLine("A");
        }

        private static void FunctionB()
        {
            Console.WriteLine("B");
        }

        private static void FunctionC()
        {
            Console.WriteLine("C");
        }
    }
这样行吗?有什么建议吗?即使这段代码有点错误:我想问另一个关于我的输出的问题-如果我启动这段代码,我会得到这样的输出:

go
end
A
B
C
C
A
B
C
A
B
C
B
A
嗯。第一个输出
go
很好,但是为什么第二个输出
end
,为什么不
A
B
C
?这正常吗,输出A,B,C在第一个随机输出之后

我不明白的下一个问题是:如果我删除Console.ReadKey()行我看不到任何输出

        static void Main(string[] args)
        {
            Console.WriteLine("go");
            Run();
            Console.WriteLine("end");
        }

我的意思是控制台正在启动,但几毫秒后它关闭,不再打开。但是它应该出现,因为我一次又一次地呼叫A、B、C,所以一个新的控制台应该一次又一次地出现。有什么想法吗?谢谢

创建计时器后,main方法立即返回。这就是为什么
end
写得这么早的原因。代码的其余部分都在其他线程中执行

计时器方法向.NET并行扩展发送三个作业,这些扩展也在后台线程中执行作业。这就是为什么您没有看到像ABC这样的订单输出,而是看到ACB、BCA CBA等等

因此,输出有一个主线程、一个计时器后台线程和最多三个工作线程(取决于CPU)

Console.ReadKey()
使邮件线程等待键盘输入。在此期间,其他线程可以处理其作业。删除
ReadKey
调用时,程序在写入
end
后立即结束,而不等待其他线程完成


不仅要将代码更改为写入开始、结束和ABC,还要将
Thread.CurrentThread.ManagedThreadID
添加到输出中。然后您可以看到哪个线程运行哪个方法。

主方法在创建计时器后立即返回。这就是为什么
end
写得这么早的原因。代码的其余部分都在其他线程中执行

计时器方法向.NET并行扩展发送三个作业,这些扩展也在后台线程中执行作业。这就是为什么您没有看到像ABC这样的订单输出,而是看到ACB、BCA CBA等等

因此,输出有一个主线程、一个计时器后台线程和最多三个工作线程(取决于CPU)

Console.ReadKey()
使邮件线程等待键盘输入。在此期间,其他线程可以处理其作业。删除
ReadKey
调用时,程序在写入
end
后立即结束,而不等待其他线程完成

不仅要将代码更改为写入开始、结束和ABC,还要将
Thread.CurrentThread.ManagedThreadID
添加到输出中。然后您可以看到哪个线程运行哪个方法。

并行(和其他类似框架)不能保证已启动任务(线程)的执行顺序。如果您想保证执行顺序是“A,B,C”,您可以将它们放入函数中,并在线程中执行

另一方面,从“主”退出会中断正在运行的线程。典型的服务必须无限期地循环,直到达到退出条件(用户按下ESC,接收信号,等等)

由于线程在单个应用程序中运行,因此它们永远不会为其输出打开新的控制台窗口。

Parallel(和其他类似框架)不能保证已启动任务(线程)的执行顺序。如果您想保证执行顺序是“A,B,C”,您可以将它们放入函数中,并在线程中执行

另一方面,从“主”退出会中断正在运行的线程。典型的服务必须无限期地循环,直到达到退出条件(用户按下ESC,接收信号,等等)


由于线程在单个应用程序中运行,因此它们将永远不会为其输出打开新的控制台窗口。

新线程在异步启动时不会阻止当前线程继续运行,甚至退出,它会停止所有子线程。在您正在执行的操作中异步启动的新线程不会阻止当前线程继续运行,甚至退出,这会停止所有子线程。