1

我有以下一段代码。我希望在多个线程上开始创建文件。目标是当我在多个线程上创建 10 个文件时将花费更少的时间。据我了解,我需要引入异步调用的元素来实现这一点。

我应该在这段代码中进行哪些更改?

using System;
using System.Text;
using System.Threading;
using System.IO;
using System.Diagnostics;

namespace MultiDemo
{
    class MultiDemo
    {
        public static void Main()
        {
            var stopWatch = new Stopwatch();
            stopWatch.Start();
            // Create an instance of the test class.
            var ad = new MultiDemo();

            //Should create 10 files in a loop.
            for (var x = 0; x < 10; x++)
            {
                var y = x;
                int threadId;
                var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
                myThread.Start();
                myThread.Join();
                //TestMethod("outpFile", y, out threadId);
            }
            stopWatch.Stop();
            Console.WriteLine("Seconds Taken:\t{0}",stopWatch.Elapsed.TotalMilliseconds);
        }

        public static void TestMethod(string fileName, int hifi, out int threadId)
        {
            fileName = fileName + hifi;
            var fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            var sw = new StreamWriter(fs, Encoding.UTF8);
            for (int x = 0; x < 10000; x++)
                {
                    sw.WriteLine(DateTime.Now.ToString());
                }
            sw.Close();
           threadId = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("{0}",threadId);
        }
    }
}

现在,如果我注释代码的线程创建部分并在循环中调用 testMethod 10 次,它比线程创建尝试处理的多个线程要快。

4

8 回答 8

5

您的代码的线程版本正在做额外的工作,因此速度较慢也就不足为奇了。

当您执行以下操作时:

var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
myThread.Start();
myThread.Join();

...你正在创建一个线程,让它调用TestMethod,然后等待它完成。 创建和启动线程的额外开销将使事情变得比TestMethod没有任何线程的调用要慢。

如果您启动所有线程工作然后等待它们完成,您可能会看到更好的性能,例如:

var workers = new List<Thread>();
for (int i = 0; i < 10; ++i) 
{
   var y = x;
   int threadId;
   var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
   myThread.Start();
   workers.Add(myThread);
}
foreach (var worker in workers) worker.Join();
于 2012-07-03T19:55:01.800 回答
1

你变慢的原因是你所做的只是启动一个新线程并等待它完成,所以它必须更慢,因为你的其他方法根本不做 3 个步骤。

试试这个(假设 .Net 4.0 因为 TPL)。在我的机器上,并行完成时始终快 100 毫秒。

[Test]
public void Y()
{
    var sw = Stopwatch.StartNew();
    Parallel.For(0, 10, n => TestMethod("parallel", n));

    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);

    sw.Restart();

    for (int i = 0; i < 10; i++)
        TestMethod("forloop", i);

    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
}


private static void TestMethod(string fileName, int hifi)
{
    fileName = fileName + hifi;
    var fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
    var sw = new StreamWriter(fs, Encoding.UTF8);
    for (int x = 0; x < 10000; x++)
    {
        sw.WriteLine(DateTime.Now.ToString());
    }
    sw.Close();
}
于 2012-07-03T19:55:24.247 回答
1

也许这并不能直接回答您的问题,但这是我对此事的看法。该代码的瓶颈不太可能是处理器。我敢打赌,磁盘 IO 会比 CPU 处理花费更多的时间因此,我不相信创建新线程会有所帮助(所有线程都将尝试写入同一个磁盘)。我认为这是过早优化的情况。如果我是你,我会在一个线程上完成所有操作。

于 2012-07-03T19:49:11.143 回答
1

在您的情况下,首先要观察的是Amdahl 定律。您的算法大致相等地使用以下每种资源:

  1. 处理器使用情况
  2. 内存访问
  3. 驱动器访问

其中,驱动器访问是迄今为止最慢的项目,因此要查看加速,您需要跨此资源并行化您的算法。换句话说,如果您通过将 10 个不同的文件写入 10 个不同的驱动器来并行化您的程序,那么与仅并行化文件内容的计算相比,您将看到显着的性能改进。事实上,如果您在 10 个不同的线程上创建文件,与驱动器访问相关的序列化实际上会降低程序的整体性能。

尽管两者都意味着多线程编程,但在 IO 的情况下,并行化不应异步编程相同。虽然我不建议您并行使用文件系统,但使用异步方法读取/写入文件几乎总是有益的。

于 2012-07-03T20:07:02.450 回答
0

您正在否定多线程的好处,因为您Join每个线程都在等待它完成,然后再创建并启动下一个线程。

相反,在创建和启动线程时将它们添加到列表中,然后循环遍历线程列表,按顺序加入它们直到它们完成。

using System.Collections.Generic;
List<Thread> threads= new List<Thread>();
//Should create 10 files in a loop.
for (var x = 0; x < 10; x++)
{
    var y = x;
    int threadId;
    var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
    threads.Add(myThread);
    myThread.Start();
    //myThread.Join();
    //TestMethod("outpFile", y, out threadId);
}
foreach (var thread in threads) thread.Join();
于 2012-07-03T19:55:15.477 回答
0

这是提高速度的错误方法,多线程并行工作,但不是加速

于 2012-07-03T19:43:33.000 回答
0

那么你为什么决定使用多线程呢?启动一个新线程的代价可能高于一个简单的循环。这不是您可以盲目决定的事情...如果您坚持使用线程,您还可以检查托管ThreadPool / async delegates的使用情况,这可以通过重用现有线程来降低创建新线程的成本。

于 2012-07-03T19:50:32.453 回答
0

尝试类似:

for (int i = 0; i < 10; ++i)  
{ 
   new Action(() => { TestMethod("outpFile"); }).BeginInvoke(null,null); 
}
Console.ReadLine();

如果它不会比串行调用更快,那么您的 IO 确实是一个瓶颈,您对此无能为力。

于 2012-07-03T20:21:09.873 回答