一个txt 大概有20W 行,我要把每行读取出来插入数据库,但是速度太慢,
如何开启20个线程去读取,然后插入数据库???

解决方案 »

  1.   

    我是先分割txt成多个string[],然后开线程去分别插入这些string[]
      

  2.   

    http://www.cnblogs.com/top5/archive/2011/01/18/1938634.html
    http://blog.163.com/yangwenwei2008@126/blog/static/61792735201192495428373/
      

  3.   

    如果楼主使用 MSSQL,倒是有个方法直接从文本文件批量导入:
    BULK INSERT aaa FROM 'c:\1.txt'  -- 文本文件  
     WITH ( 
          FIELDTERMINATOR = ',' ,  -- 字段分隔符,默认为 \t         
          ROWTERMINATOR =   '.' ,  -- 行分隔符,默认为 \r\n
          FIRSTROW=0               -- 跳过行数
     )
      

  4.   


    你的CPU一直是100%么?如果你的CPU运行有空闲,磁盘使用有空闲,为什么就随便说是“资源不足”呢?多线程编程稍微复杂一点,因此我认为lz这样的仅仅靠道听如说的方式(而没有教练的方式)从csdn也学不到什么合适的多线程编程方法。我不认为现在的机器还是10几年前的机器,我不认为我们几乎所有人的机器(我们的高档的CPU、各种外设)不能好好地支持多线程。
      

  5.   

    我没有说“资源不足”,另外这里和CPU没有半毛钱的关系,读写文件是有I/O的速度决定的,同一个文件肯定是存在同一块磁盘,而磁盘I/O就一个,多线程访问了,反而会导致I/O的中断分配给多个线程,一个中断多个线程轮流分配,速度肯定比给一个线程处理到结束慢的多,这也是磁盘测速的时候,为什么大文件的速度比小文件快得多,GHOST的速度比直接复制粘贴的速度快得多的道理。而数据库则更需要考虑内部的事务同步,有主键的情况下,多线程操作内部自动加锁处理的,防止主键冲突,这里面也需要开销。多线程只有处理不同任务的时候才有效果,同一个任务分开做,只会降低效率。
      

  6.   

    用FileStream的重载试下
    var fs = new System.IO.FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 5120, FileOptions.Asynchronous);
    瓶颈在硬盘和总线,用线程把CPU耗完也没用
      

  7.   

    同意,多线程只是多任务,对于效率来说,不一定提高.如果是插入语句,可以看一下oracle的批量插入,也许会提高效率,挥着用,prepare();就读取文件来说,只能用reader吧.
      

  8.   

    我没有说“资源不足”,另外这里和CPU没有半毛钱的关系,读写文件是有I/O的速度决定的,同一个文件肯定是存在同一块磁盘,而磁盘I/O就一个,多线程访问了,反而会导致I/O的中断分配给多个线程,一个中断多个线程轮流分配,速度肯定比给一个线程处理到结束慢的多,这也是磁盘测速的时候,为什么大文件的速度比小文件快得多,GHOST的速度比直接复制粘贴的速度快得多的道理。而数据库则更需要考虑内部的事务同步,有主键的情况下,多线程操作内部自动加锁处理的,防止主键冲突,这里面也需要开销。多线程只有处理不同任务的时候才有效果,同一个任务分开做,只会降低效率。我只听说过中断嵌套,没听说过一个中断能多个线程轮流分配。。或者你说的中断不是datasheet里的interrupt而是别的什么东西。。另外磁盘IO都是通过DMA了,不是靠CPU去写。。GHOST速度快的原因是不考虑已有文件直接连续写盘,直接复制粘贴慢是因为要来回读写FAT、MFT之类的,所以会慢些。。另外。。1#的小哥做法真是得儿
      

  9.   

    我没有研究过那个原理,只是举例而已,难免有不当之处。我的多年的经验告诉我,这里肯定不适合拆出多线程,我只是为了表达这个意思而已,实际影响速度的因素很多,拆分线程处理的话,只会减慢速度。单线程的GHOST都可以达到最快的处理速度(DOS下面只能单线程),可见不是多线程了就可以如何如何的。
      

  10.   

    不管是读文件还是写数据库,对于普通硬盘来说这种情况多线程只会更慢,决策与CPU或者DMA没有关系。
    如果内存不够(非批量操作)或者文件与数据库位于不同的存储介质,读文件与写数据库应该有各自的线程处理。
      

  11.   

    不管是否DMA(DMA主要是异步实现,CPU一般都不会成为瓶颈),磁头只有一个,有序访问总是最好的,硬盘IOCP的要点就是尽量有序访问硬盘。
      

  12.   

    有一个错误,硬盘IOCP的要求是磁头尽量的少移动。
      

  13.   

    sp大神这次出错啦。
    这里的“资源”可不仅仅是cpu或内存,
    还包括io和irq(这应该就是木桶效应的最低处了)事实上除了那些分布式/大数据,等“高端”应用,常规应用中,
    是否需要多线程,应该是从业务模型和需求逻辑来分析。比如确实是有多组数据模型需要运行,同时这些模型的参数不确定、不一致。
    单纯只在性能角度去做并行优化,除了多请求并发这块,还没发现其他情况需要的。
      

  14.   

    现在的电脑瓶颈都在磁盘而不在CPU,CPU几线程就开几条线程执行读取就能充分利用CPU了,不过读取文件的话瓶颈还在磁盘
      

  15.   

    多线程主要作用是抢CPU!如果同时开的进程少,单线程多线程无所谓,只有多核多线程,有点小作用!
      

  16.   

    有的时候  感觉一个线程跑不完  cpu资源  多线程  可能能跑完所以   你们懂的有时候  虽然知道理论   是这样   但理论和实际是有差别的
      

  17.   


    好吧 bs做多了,winform那确实了
     不过其实也简单,考虑业务的时候忽视ui线程,完全就只做交互和显示用,不参与任何业务和运算逻辑。
    只要是执行业务的 都封装一次,在后台线程里完成,那么对于后台线程来说,其实还是单线程的思路了。
      

  18.   

    兄弟 20w  插入 很快的 秒内 都可以完成了  打包成list  然后分批 来批量插入 
    不要 一条条插入 
      

  19.   

    额 难道我的话没有表达出“多线程和UI没什么关系”这个论点么?
    ui是交互线程,后台是工作线程,能把这两者分的比较清楚,就不会纠结什么多线程了。
      

  20.   

    20万行应该不多啊
    那就string[] AllLine = File.ReadAllLine(@"c://1.txt");
    Foreach(var item in AllLine){
       Insert(item);
    }非得用多线程
    读的时候应该不可能 再说20万行数据不多File.ReadAllLine 一分钟足可以读出来了
    写入20万行也不多啊 你也可以开个线程 但是你要怎么管理?
    开四个线程for(int i = 0 ; i < 4;i++){
                Thread t = new Thread(()=>{
                  int Start = i*50000;
                  int End = Start+5000;
                  for(int temp = Start;temp<End;temp++){
                         Insert( AllLine[temp]);
    }
    });
    t.Start();
    t.IsBackground = true;
    }
      

  21.   

    你没看到我意思。。没必要区分前台后台。。 whatever,从业者的思维我是搞不懂的。。
      

  22.   

    说这么多不如直接试一试
    IT狗都是只会嘴巴说的么
    狗一样的
    测试机
    测试文件 189MB
    注:以下速度均经多次试验单线程 3.5秒
    2线程 2.0秒。。谁说多线程不能提高速度,这个响亮的嘴巴抽的你爽不?
    3线程 3.08秒  速度略有降低
    4线程 3.44秒 更慢
    8线程 3.74秒 继续慢
    16线程  3.46秒  这以后基本是单线程的速度了
    至于这些现象表示了什么,原理是什么,自己研究吧
      

  23.   

    我来汪两声。不废话,先上测试代码        static void Main(string[] args)
            {
                fileThread fileThread = new fileThread(@"E:\data\WebSite\ShowJim.com.rar", @"e:\windows2003sql2000.GHO");
                for (int threadCount = 1; threadCount != 10; ++threadCount) fileThread.WaitThread(threadCount);            Console.WriteLine("end...");
                Console.ReadKey();
            }
            /// <summary>
            /// 多线程文件读取测试
            /// </summary>
            private class fileThread
            {
                /// <summary>
                /// 测试文件名
                /// </summary>
                private string fileName;
                /// <summary>
                /// 硬盘缓存刷新文件名,文件必须大于空闲内存数量
                /// </summary>
                private string memoryCacheFileName;
                /// <summary>
                /// 测试线程数量
                /// </summary>
                private int threadCount;
                /// <summary>
                /// 已完成线程数量
                /// </summary>
                private int finallyThreadCount;
                /// <summary>
                /// 测试文件数据缓冲区
                /// </summary>
                public byte[] Data { get; private set; }
                /// <summary>
                /// 多线程同步访问锁
                /// </summary>
                private readonly object threadLock = new object();
                /// <summary>
                /// 多线程文件读取测试
                /// </summary>
                /// <param name="fileName">测试文件名</param>
                /// <param name="memoryCacheFileName">硬盘缓存刷新文件名,文件必须大于空闲内存数量</param>
                public fileThread(string fileName, string memoryCacheFileName)
                {
                    this.fileName = fileName;
                    this.memoryCacheFileName = memoryCacheFileName;
                    using (System.IO.FileStream file = System.IO.File.OpenRead(fileName)) Data = new byte[file.Length];
                    Console.WriteLine("测试文件: " + fileName + " 文件大小: " + Data.Length.ToString() + "B");
                    using (System.IO.FileStream file = System.IO.File.OpenRead(memoryCacheFileName))
                    {
                        Console.WriteLine("硬盘缓存刷新文件: " + memoryCacheFileName + " 文件大小: " + file.Length.ToString() + "B");
                    }
                }
                /// <summary>
                /// 测试开始
                /// </summary>
                /// <param name="threadCount">测试线程数量</param>
                public void WaitThread(int threadCount)
                {
                    #region 硬盘缓存刷新
                    byte[] data = new byte[1 << 20];
                    using (System.IO.FileStream file = System.IO.File.OpenRead(memoryCacheFileName))
                    {
                        for (int count = (int)(file.Length / data.Length); count != 0; --count) file.Read(data, 0, data.Length);
                    }
                    #endregion                System.Diagnostics.Stopwatch time = new System.Diagnostics.Stopwatch();
                    time.Start();                this.threadCount = threadCount;
                    finallyThreadCount = 0;
                    while (threadCount != 0) new System.Threading.Thread(read).Start(threadCount--);
                    System.Threading.Monitor.Enter(threadLock);
                    System.Threading.Monitor.Wait(threadLock);
                    System.Threading.Monitor.Exit(threadLock);                time.Stop();
                    Console.WriteLine("测试线程数量: " + finallyThreadCount.ToString() + " 测试文件消耗时间: " + time.Elapsed.TotalSeconds.ToString() + "s");
                }
                /// <summary>
                /// 读取文件线程处理
                /// </summary>
                /// <param name="threadNO">线程序号</param>
                private void read(object threadNO)
                {
                    int length = Data.Length / threadCount, thread = (int)threadNO, startIndex = (thread - 1) * length;
                    using (System.IO.FileStream file = System.IO.File.OpenRead(fileName))
                    {
                        file.Seek(startIndex, System.IO.SeekOrigin.Begin);
                        file.Read(Data, startIndex, thread == threadCount ? Data.Length - startIndex : length);
                    }
                    System.Threading.Monitor.Enter(threadLock);
                    if (++finallyThreadCount == threadCount) System.Threading.Monitor.Pulse(threadLock);
                    System.Threading.Monitor.Exit(threadLock);
                }
            }再上测试结果,多次测试结果相差不大测试文件: E:\data\WebSite\ShowJim.com.rar 文件大小: 310455126B
    硬盘缓存刷新文件: e:\windows2003sql2000.GHO 文件大小: 2147480201B
    测试线程数量: 1 测试文件消耗时间: 10.3381957s
    测试线程数量: 2 测试文件消耗时间: 27.9140871s
    测试线程数量: 3 测试文件消耗时间: 37.9860107s
    测试线程数量: 4 测试文件消耗时间: 34.3607919s
    测试线程数量: 5 测试文件消耗时间: 33.5778776s
    测试线程数量: 6 测试文件消耗时间: 31.7799228s
    测试线程数量: 7 测试文件消耗时间: 31.6020692s
    测试线程数量: 8 测试文件消耗时间: 39.1524914s
    测试线程数量: 9 测试文件消耗时间: 41.1798792s
    end...
    对于#38那个人类的测试结果,我有3点疑问:
    1.测试程序是否正确?
    2.每次测试是否刷了windows操作系统的硬盘缓存?(windows会将大部分空闲内存作为硬盘缓存)
    3.2线程接近100MB/s的读取速率,不知道是磁盘阵列还是固态硬盘?(我在#18已经汪过了,叫的是普通硬盘)
      

  24.   


    1.我自认为不会写错程序,尽管没学过xx原理bla bla的
    2.每次测试重启虚拟机
    3.如图,渣电脑一台
    其实不必和我纠结,我对这些东西不感兴趣,很久不玩编程了,没什么意思
      

  25.   


    求私信 MP4文件读写库!大神 好久没见啊FileStream。
      

  26.   

    这事的瓶颈在于硬盘的性能上吧,无论你是几个线程,把硬盘读取速度撑满了事啊。
    而硬盘读取速度又因为当前文件缓存,硬盘本身缓存使用,甚至文件内容本身所在磁道位置,而会有不同的速度曲线。我觉得不同环境里面对多线程读取文件的测试结果会有不一样的结果,但是整体来说,读取速度一定不会超过某一上限,至于最快的是单线程还是多线程,和当前测试环境又有很大的关系。换句话说,你们这测试都是白干了啊!最后回到楼主的问题,你这问题一点意义都没有。线程并不能显著提高文件读写性能,需要提高性能首先要知道性能的瓶颈在什么地方。
    20w行文件读取的速度不会比20w行插入数据库更慢。你的性能要提高顶多是弄个内存缓存区,读取插入各一个线程,文件读取后填入,插入那边只管缓存区是否有数据,这样整体速度取决于最慢的那一方了。PS:眼镜兄今天火气很大啊!
    对于虚拟机有两点疑问:
    1.虚拟机硬盘访问最终还是要访问宿主系统的硬盘缓存,启动虚拟机能否刷掉宿主系统的硬盘缓存要看空闲内存的大小、启动虚拟机读取量、虚拟机系统实际使用内存大小。
    2.虚拟机访问硬盘是存在非硬盘访问阻塞因素的(源于虚拟机对于硬盘的文件的组织结构管理),影响类似于360流氓软件(当然影响没有那么严重)。当然随着虚拟机的流行,虚拟机测试也是一种应该考虑的情况,也许可以这样说:虚拟机中大文件的访问使用多线程能够提高效率。
      

  27.   

    都说了我并不在乎测试结果是怎样,或者原理怎样,bla bla,这不关我事。我不会编程,只是一来凑凑热闹,二来喷一喷有些信口开河纸上谈兵的挨踢狗。。不过好像变成群嘲,伤害了有些幼小的心灵whatever,I don't care。。另外,诚恳的建议,别让工作绑架自己的思维方式,要知道,天地还是很广阔的
      

  28.   

    记得.NET 4.5后可以使用内存 方式读取 流文件
      

  29.   

    另外,大量零碎文件操作,建议使用异步操作(硬盘IOCP),让系统自己选择最佳的读写次序。
      

  30.   

    每读取5000条数据再给数据库添加一次,这样效率应该会提高不少。可以用SqlBulkCopy批量添加
      

  31.   

    你的FileStream会占用当前文件资源 其他的人无法访问
    你是怎么做到多线程读取的
      

  32.   

    理论上如果有双磁头双cpu的话确实可以提速一倍.
    线程太多反倒会有反效果.ps: 在hadoop普及的时候,单机的优化都是小儿科.
    ps2: 不懂原理不是你的错,但不懂原理还理直气壮就只能一辈子当码农了.
      

  33.   

    用的是什么数据库?SQL的话可以用bcp ,其他大型数据库相信也有,这些很普遍的问题其实数据库已经有成熟的解决方案了,一条一条插数据让我想起了我还在念初中的时光