希望这个问题比我之前的问题好。我有一个。exe,我将传递不同的参数(文件路径),然后它将接受和解析。所以我将有一个循环,在一个列表中遍历文件路径并将它们传递给这个。exe文件。
为了提高效率,我想把执行分散到多个核心,我认为你可以通过线程来实现。
我的问题是,我应该使用线程池,或多个线程来异步运行这个。exe ?
另外,根据你们认为哪一个是最好的,如果你能给我一个教程,将有一些信息,我想做什么。谢谢你!
编辑:我需要将.exe的执行次数限制为每核心执行一次。这是最有效的,因为如果我解析100,000个文件,我不能只启动100,000个进程。因此,我使用线程将一次执行的数量限制为每个内核执行一次。如果有其他方法(除了线程)来发现处理器是否在执行中没有被绑定,或者.exe是否已经完成,请解释。但如果没有另一种方式,我最后的问题是我如何使用一个线程调用解析方法,然后回调时,该线程不再使用?
第二次更新(非常重要):
我把每个人告诉我的都看了一遍,发现了一个我认为不重要的关键因素。所以我正在使用GUI,我不希望它被锁定。这就是为什么我想使用线程。我现在的主要问题是,我如何从线程发送回信息,以便我知道何时执行结束?
正如我在回答你之前的问题时说的,我认为你不理解进程和线程之间的区别。进程非常"繁重"(*);每个进程可以包含多个线程。如果你从父进程中生成新进程,父进程不需要创建新线程;每个进程都有自己的线程集合。
只在父进程中创建线程,如果所有的工作都在同一个进程中完成。
把线程想象成一个工人,把进程想象成一个包含一个或多个工人的建筑。
一个策略是"建造一个单独的建筑物,并在其中填充10个工人,每个人做一定数量的工作"。你得到了构建一个进程和十个线程的费用。
如果你的策略是"建一座大楼。然后让该建筑中的一名工人下令建造1000多座建筑,每座建筑中都有一名工人按照他们的要求去做",然后你就得到了建造1001座建筑和雇佣1001名工人的费用。
你想而不是追求的策略是"建造一座大楼"。在那栋楼里雇1000名工人。然后指示每个工人建造一座建筑物,然后有一个工人去做真正的工作。"创建一个线程的唯一任务是创建一个进程,然后这个进程又创建一个线程,这是没有意义的!你有1001栋楼和2001名工人,其中一半立即闲置,但仍然需要支付工资。
看看你的具体问题:关键问题是"瓶颈在哪里?"生成新进程或新线程只有在性能问题是由处理器控制的情况下才有帮助。如果解析器的性能不是取决于解析文件的速度,而是取决于将文件从磁盘上取出的速度,那么并行化将使变得非常非常糟糕。您将有大量的系统资源用于同时处理同一个磁盘控制器,并且随着负载的增加,磁盘控制器将变得越来越慢。更新:
我需要将.exe的执行次数限制为每核心执行一次。这是最有效的,因为如果我解析100,000个文件,我不能只启动100,000个进程。因此,我使用线程将一次执行的数量限制为每个内核执行一次。如果有其他方法(除了线程)来发现处理器是否在执行中没有被绑定,或者.exe是否已经完成,请解释
这似乎是一种非常复杂的方法。假设你有n个处理器。你提出的策略,据我所知,是启动n个线程,然后让每个线程启动一个进程,你知道,由于操作系统将可能每个CPU调度一个线程,以某种方式处理器也将神奇地调度每个新进程中的新线程在不同的CPU上?
这似乎是一个曲折的推理链,取决于操作系统的实现细节。这太疯狂了。如果您想设置特定进程的处理器关联,只需在该进程上设置处理器关联!不要用线程做这种疯狂的事情,希望它能解决。
我的意思是,如果你想让一个可执行程序运行的实例不超过n个,每个处理器一个,那就不要把线程搞得一团糟。相反,只让一个线程处于循环中,不断地监视正在运行的进程。如果运行的可执行文件副本少于n个,则生成另一个副本,并将设置为您最喜欢的CPU 。如果有n个或更多的可执行文件副本正在运行,请休眠一秒钟(或一分钟,或任何有意义的时间),当您醒来时,再次检查。一直这样做,直到你完成为止。这似乎是一个更简单的方法。
(*)线程也很重,但它们比进程轻。
我会自发地将文件路径推到一个线程安全的队列中,然后启动一些线程(比如每个核心一个)。每个线程将重复地从队列中弹出一个项目,并相应地处理它。当队列为空时完成工作。
实现建议(回答评论中的一些问题):
队列:
在c#中,你可以看看Queue类和Queue。实现队列的同步方法:
"此类型的Public static(在Visual Basic中共享)成员是线程安全的。不能保证任何实例成员都是线程安全的。为了保证Queue的线程安全,所有操作都必须通过Synchronized方法返回的包装器来完成。在集合中枚举本质上不是线程安全的过程。即使在集合同步时,其他线程仍然可以修改集合,这将导致枚举数抛出异常。为了保证枚举期间的线程安全,您可以在整个枚举期间锁定集合,也可以捕获由其他线程所做更改引起的异常。"
线程:
对于线程部分,我认为msdn线程教程中的任何示例都可以(该教程有点旧,但应该有效)。不需要担心同步线程,因为它们可以彼此独立地工作。上面的队列是它们应该需要访问的唯一公共资源(因此队列的线程安全性很重要)。
启动外部进程:
下面的代码是从如何使用Visual c#等待shell应用程序完成中借用(并进行了调整)的。您需要根据自己的需要进行编辑,但作为初学者:
//How to Wait for a Shelled Process to Finish
//Create a new process info structure.
ProcessStartInfo pInfo = new ProcessStartInfo();
//Set the file name member of the process info structure.
pInfo.FileName = "mypathmyfile.exe";
//Start the process.
Process p = Process.Start(pInfo);
//Wait for the process to end.
p.WaitForExit();
伪代码:
Main thread;
Create thread safe queue
Populate the queue with all the file paths
Create child threads and wait for them to finish
Child threads:
While queue is not empty << this section is critical, not more then one
pop file from queue << thread can check and pop at the time
start external exe
wait for it....
end external exe
end while
Child thread exits
Main thread waits for all child threads to finish
Program finishes.
如何找出内核的数量参见这个问题。
则使用Parallel。在MaxDegreeOfParallelism设置为内核数的情况下,使用ParallelOptions执行ForEach。
Parallel.ForEach(args, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, (element) => Console.WriteLine(element));
如果你的目标是。net 4框架的并行。为或平行。每个人都非常有帮助。如果这些不符合你的要求,我已经找到了任务。工厂应该是有用和直接使用的。
要回答你修改后的问题,你需要流程。您只需要创建运行exe的正确数量的进程。不要担心将它们强制放到特定的核心上。Windows会自动完成。
怎么做:
您想要确定机器上的核数。您可能只是知道它,并硬编码它,或者您可能想使用System.Environment.ProcessorCount
之类的东西。
创建List<Process>
对象
那么您想要使用System.Diagnostics.Process.Start
启动那么多进程。返回值将是一个进程对象,您将希望将其添加到List中。
现在重复以下操作,直到完成:
呼叫Thread.Sleep
稍等。也许一分钟左右。
遍历列表中的每个Process
,但确保使用for
循环而不是foreach
循环。对于每个进程,调用Refresh()
,然后检查每个进程的'HasExited'属性,如果它是true,使用Process.Start
创建一个新进程,并用新创建的进程替换列表中退出的进程。
如果您正在启动。exe,那么您别无选择。您将在单独的进程中异步运行此操作。对于执行启动的程序,我建议您使用单个线程,并保留您启动的进程列表。
每个启动的exe将在其自己的进程中发生。你不需要使用线程池或多个线程;操作系统管理进程(因为它们是进程而不是线程,所以它们是非常独立的;完全独立的内存空间等)。