1

这是我的C#控制台程序,它使用 Powerpoint 将文件转换ppt为 s 的文件夹png。这应该是一个在自己的服务器上运行的自动化过程。

我希望一旦线程从文件创建图像,它应该立即删除图像和源文件。

实际行为是,如果五个线程正在运行,它将等待创建五个图像文件夹,然后任何线程才能移动任何文件。我能够看到正在创建的图像,并将其与Console读数进行比较,因此我可以看到线程没有尝试移动文件。

只有在所有其他线程都制作了它们的图像之后,任何线程才会尝试移动文件。我怀疑这是错误的。

这是一个 Amazon EC2 中型实例,它似乎会耗尽 CPU,因此五个线程可能太多了。

我还发现,当这个程序运行时,我几乎不能使用 Windows 资源管理器。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using Microsoft.Office.Core;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using System.Diagnostics;
using System.Timers;

namespace converter
{
    class Program
    {
        public static int threadLimit=0;
        public static int currThreads = 0;
        static void Main(string[] args)
        {
            var inDir = args[0];
            var outDir = args[1]+"\\";
            var procDir = args[2]+"\\";
            Int32.TryParse(args[3],out threadLimit);
            Thread[] converterThreads = new Thread[threadLimit];
            while (true)
            {
                System.Threading.Thread.Sleep(1000);
                var filePaths = Directory.GetFiles(inDir, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".pptx") && !s.Contains("~$") || s.EndsWith(".ppt") && !s.Contains("~$"));
                var arrPaths = filePaths.ToArray();
                for(var i=0; i< arrPaths.Length; i++)
                {
                    if (currThreads < threadLimit && currThreads < arrPaths.Length)
                    {
                        Console.WriteLine("currThreads= " + currThreads + " paths found= " + arrPaths.Length);
                        try
                        {
                            var fileNameWithoutExtension = arrPaths[currThreads].Replace(inDir, "").Replace(".pptx", "").Replace(".ppt", "").Replace("\\", "");
                            var filenameWithExtension = arrPaths[currThreads].Substring(arrPaths[currThreads].LastIndexOf("\\") + 1);
                            var dir = arrPaths[currThreads].Replace(".pptx", "").Replace(".ppt", "");


                            Conversion con = new Conversion(arrPaths[currThreads], dir, outDir, procDir, filenameWithExtension, fileNameWithoutExtension);
                            converterThreads[i] = new Thread(new ThreadStart(con.convertPpt));
                            converterThreads[i].Start();
                            Console.WriteLine(converterThreads[i].ManagedThreadId + " is converting " + fileNameWithoutExtension);

                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(string.Format("Unable to convert {0} ", arrPaths[i]) + e);
                        }
                    }

                }
                for (var i = 0; i < converterThreads.Length; i++)
                {
                    if (converterThreads[i] != null)
                    {
                        if (!converterThreads[i].IsAlive)
                        {
                            converterThreads[i].Abort();
                            converterThreads[i].Join(1);
                            Console.WriteLine("thread " + converterThreads[i].ManagedThreadId + " finished, "+currThreads+" remaining");
                            converterThreads[i] = null;
                        }
                    }
                }

                if (currThreads == 0)
                {
                    try
                    {
                        foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
                        {
                            proc.Kill();
                        }
                    }
                    catch (Exception e3)
                    {
                    }
                }

            }
        }
    }

    class Logger{

        static void toLog(String msg)    
        {
                //TODO: log file    
        }

    }

    class Conversion{
        static int numberOfThreads=0;
        String input;
        String output;
        String outDir;
        String process;
        String nameWith;
        String nameWithout;
        int elapsedTime;
        System.Timers.Timer time;
        public Conversion(String input, String output, String outDir, String processDir, String nameWith, String nameWithout)
        {
            this.input = input;
            this.output = output;
            this.outDir = outDir;
            process = processDir;
            this.nameWith = nameWith;
            this.nameWithout = nameWithout;
            numberOfThreads++;
            Console.WriteLine("number of threads running: " + numberOfThreads);
            Program.currThreads = numberOfThreads;
            time = new System.Timers.Timer(1000);
            time.Start();
            time.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            elapsedTime = 0;
        }

        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            elapsedTime++;

        }

        public void convertPpt()
        {

            var app = new PowerPoint.Application();
            var pres = app.Presentations;
            try
            {
                var file = pres.Open(input, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);
                file.SaveAs(output, Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsPNG, MsoTriState.msoTrue);
                file.Close();
                app.Quit();
                Console.WriteLine("file converted " + input);
            }
            catch (Exception e)
            {
                Console.WriteLine("convertPpt failed");
            }

            moveFile();
            moveDir();

        }
        public void moveFile()
        {
            Console.WriteLine("moving" + input);
            try
            {
                System.Threading.Thread.Sleep(500);
                Console.WriteLine(string.Format("moving {0} to {1}", input, process + nameWith));
                if (File.Exists(process + nameWith))
                {
                    File.Replace(input, process + nameWith, null);
                }
                else
                {
                    File.Move(input, process + nameWith);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(string.Format("Unable to move the file {0} ", input) + e);
                try
                {
                    foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
                    {
                        proc.Kill();
                    }
                }
                catch (Exception e3)
                {
                }
            }
        }

        public void moveDir()
        {
            Console.WriteLine("moving dir " + output);

            try
            {
                System.Threading.Thread.Sleep(500);
                Console.WriteLine(string.Format("moving dir {0} to {1} ", output, outDir + nameWithout));

                if (Directory.Exists(outDir + nameWithout))
                {
                    Directory.Delete(outDir + nameWithout, true);
                }
                if (Directory.Exists(output))
                {
                    Directory.Move(output, outDir + nameWithout);
                }

            }
            catch (Exception e)
            {
                Console.WriteLine(string.Format("Unable to move the directory {0} ", output) + e);
                try
                {
                    foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
                    {
                        proc.Kill();
                    }
                }
                catch (Exception e3)
                {
                }
            }
            finally
            {
                numberOfThreads--;
                Program.currThreads = numberOfThreads;
                Console.WriteLine("took " + elapsedTime + "seconds");
            }
        }
    }
}
4

1 回答 1

5

每 1000 毫秒,您会获得一个文件列表,inDir并可能启动一个线程来处理每个文件。关于是否启动新线程以及如何管理线程的生命周期,您有非常复杂的逻辑。

逻辑太复杂,我无法在不调试代码的情况下发现错误。但是,我会提出一个替代方案。

让一个线程监视新文件并将文件路径放入文件的BlockingCollection中以进行处理。该线程什么也不做。

有 N 个额外的线程从 中检索文件路径BlockingCollection并处理它们。

这被称为生产者/消费者模式,非常适合您正在做的事情。

链接的 MSDN 页面底部的示例代码显示了一个实现示例。

在旁注中,您正在捕捉和吞咽Exception e3。不要抓住你不会处理的东西,它会隐藏问题。

于 2013-11-05T00:39:52.730 回答