我有以下代码。我希望在多个线程上启动文件创建。目标是当我在多个线程上创建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次,那么它比线程创建尝试处理的多个线程更快。
答案 0 :(得分: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();
答案 1 :(得分:1)
也许这并没有直接回答你的问题,但这是我对此事的想法。该代码中的瓶颈不太可能是处理器。我敢打赌,磁盘IO会比CPU处理时间方式更多时间。因此,我不认为创建新线程会有所帮助(所有线程都会尝试写入同一个磁盘)。我认为这是一个过早优化的案例。如果我是你,我会在一个线程上完成所有工作。
答案 2 :(得分:1)
你速度慢的原因是你正在做的就是启动一个新线程并等待它完成所以它必须更慢,因为你的另一个方法就是不做3步。
尝试一下(假设因为TPL而使用.Net 4.0)。在我的机器上,并行完成时,它始终快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();
}
答案 3 :(得分:1)
在您的案例中要注意的主要事项是Amdahl's Law。您的算法大致相同地使用以下每个资源:
其中,驱动器访问到目前为止是最慢的项目,因此要查看加速,您需要在此资源上并行化算法。换句话说,如果通过将10个不同的文件写入10个不同的驱动器来并行化您的程序,那么与仅仅并行化文件内容的计算相比,您将看到显着的性能提升。实际上,如果您在10个不同的线程上创建文件,那么涉及驱动器访问的序列化实际上可能会降低程序的整体性能。
虽然两者都暗示多线程编程,但在IO的情况下,并行化 NOT 应与异步编程相同。虽然我不建议并行使用文件系统,但使用异步方法读取/写入文件几乎总是有益的。
答案 4 :(得分:0)
这是提高速度的错误方法,并行工作的多线程,但不是加速
答案 5 :(得分:0)
那你为什么决定使用多线程呢?启动新线程的价格可能高于简单循环。它不是你可以盲目决定的......如果你坚持使用线程,你也可以检查ThreadPool的托管async delegates /用法,这可以降低创建新线程的成本 - 使用现有的。
答案 6 :(得分: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();
答案 7 :(得分:0)
尝试类似:
for (int i = 0; i < 10; ++i)
{
new Action(() => { TestMethod("outpFile"); }).BeginInvoke(null,null);
}
Console.ReadLine();
如果它不会比串行呼叫更快,那么你的IO确实是一个瓶颈,你无能为力。