正常点的解决方法就是额外加一个字段用于记录当前行的处理状态
比如初始值是0,处理中是1,完成是2,失败代码是100开头的自定义序列丢出去若干个exe,每个exe分20个线程跑,每次每个exe取一千或若干条记录,同时更新他们的处理状态为处理中,干完以后批量更新处理完成不过你那才几十万条记录,就单个exe不加字段直接运行估计也完事了,写一点本地文件做log,标记一下处理到第几行以及失败的主键值

解决方案 »

  1.   

    1,如何每次只读取100条到队列里呢,这个也需要一个线程来监听吗?
    当然需要一个额外的线程负责调度那些下载的线程.都让主线程去做,不怕阻塞UI影响显示么?
    如果是SQL SERVER数据库,有TOP关键字,可以只读取一部分数据.其他数据库暂时不知道怎么办,几十万不多,都读出来算了.2,下载完一条就去数据库删除一条吗?
    也可以都下载完批量删除,省事.3,如何才能保证多线程操作时不会撞车,如同一条数据被2线程下载2次
    多线程操作同一个队列,当然是加锁了
      

  2.   

    你到底是求代码,还是求思路?
    如果你不知道如何开线程,如何访问数据库,如何下载,我们说再多也没用.开线程,访问数据库都没问题,就是卡在了如何多线程循环执行同一任务上例如:   private void button2_Click(object sender, EventArgs e)
            {            Thread th1 = new Thread(Reader);
                th1.Start();
                
            }
            public void down_pic(String m_id)
            { 
            //所有线程都调用这个方法干活
            }
            //读取数据库图片地址
            public void Reader()
            {            sql_class conn = new sql_class();
                SqlDataReader sqlread = conn.getread("SELECT TOP 100 [id],[m_id],[h_id],[pic_name],[pic_url] FROM [temp]");
                    while (sqlread.Read())
                    {
                        //这里调用线程来执行方法
                        Thread thread = new Thread(() => down_pic(sqlread[0].ToString()));
                        thread.Start();  
                    }                 }我上面的方法倒是可以实现多线程,但是这个线程是完全不受控制的,也就是说可能会开启100个线程,但是我的目的是只开启10个线程来慢慢下载这些任务。现在就是卡在如何让线程执行完一个任务以后,不关闭,再去执行下一个任务。从来没搞过这样的,一点经验都没有
      

  3.   

    不要在while里面开线程,那样数据库有几十万数据,岂不是开几十万个线程,崩溃...
    先开一个线程,然后执行查询,查询后结果ADD进LIST
    然后在这个线程里再开10个线程,执行同一个方法,就是去LIST里取一条数据,取出一条,就REMOVE一条,这样可以避免重复任务
    当然写入LIST,读取LIST和删除LIST,这些都要加锁,避免同时进行出错之后就简单了,既然每个线程都取到了一个不同的任务,就开始执行吧
    执行完回到开始(用循环),再去取任务,再执行,直到队列里已经没有任务了,退出
      

  4.   

    当然,如果你查出来直接就在datatable里了,不另外定义LIST也行,线程都去直接操作datatable.
    最好事先copy个副本,方便之后在原始datatable里记录些信息或用它来更新数据库.
      

  5.   

    至于查询数据库的线程,看你想如何设计了.
    1.可以一次性都查出来,然后就一直处理.
    2.也可以查100条,开10个线程,然后等待,等线程都退出了,再次查100条,再开10个线程
    3.也可以完全分开,先查100条,然后开10个线程,然后不断的去看队列里还剩多少任务,不足20了,就再查100条ADD进去
      

  6.   

    具体哪里不会写?不要告诉我都不会...
    能不能具体点,比如锁如何加,LIST如何操作等等...
      

  7.   


    目前已经实现了读取数据库添加到队列,不知道如何使用线程来操作这些队列具体代码:
     Queue qu = new Queue();//创建队列
            //下载图片回来
            private void button2_Click(object sender, EventArgs e)
            {            Thread th1 = new Thread(Reader);
                th1.Start();
                
            }
            //执行图片下载
            public void down_pic(String id,String m_id,String h_id,String pic_name,String pic_url,String list)
            {
                String p = upload + m_id+"\\"+h_id+"\\"; //保存目录地址 
                if (makefile(p) == false)//创建文件夹
                {
                    MessageBox.Show("无法创建文件夹,可能的原因有:\n没有磁盘写入权限\n要创建的目录错误\n路径:" + p + "");
                    return;
                }
                Save_img(weburl+ pic_url, http+list, p + pic_name);//保存图片到指定路径        }
            //读取数据库到队列
            public void Reader()
            {
                String id;
                String m_id;
                String h_id;
                String pic_name;
                String pic_url;
                String list;
                sql_class conn = new sql_class();
                if (qu.Count < 10)
                {
                    SqlDataReader sqlread = conn.getread("SELECT TOP 100 [id],[m_id],[h_id],[pic_name],[pic_url],[list] FROM [temp]");
                    if (sqlread.Read())
                    {
                        while (sqlread.Read())
                        {
                            id = sqlread[0].ToString();
                            m_id = sqlread[1].ToString();
                            h_id = sqlread[2].ToString();
                            pic_name = sqlread[3].ToString();
                            pic_url = sqlread[4].ToString();
                            list = sqlread[5].ToString();
                            qu.Enqueue(id + "#" + m_id + "#" + h_id + "#" + pic_name + "#" + pic_url + "#" + list);
                        }                                     
                    }
                    else
                    {
                        return; //终止读库任务
                    }
                }
                Delay(10000);//等待10秒
                //Reader(); //重复查询 
            }
            ///////////////////////////////////以下为公用方法////////////////////////////////////////        //创建文件夹
            public bool makefile(String path)
            {
                try
                {
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                        return true;
                    }
                }
                catch
                {
                    return false;
                }
                return true;
            }        //图片保存到指定目录
            public Bitmap Save_img(String pic_url, String Ref, String path)
            {
                Bitmap img = null;
                HttpWebRequest req;
                HttpWebResponse res = null;
                try
                {
                    System.Uri httpUrl = new System.Uri(pic_url);
                    req = (HttpWebRequest)(WebRequest.Create(httpUrl));
                    req.Timeout = 5000;
                    req.Host = "auto.mangafiles.com";
                    req.Method = "GET";
                    req.Referer = Ref;    //伪装浏览器头
                    res = (HttpWebResponse)(req.GetResponse());
                    img = new Bitmap(res.GetResponseStream());//获取图片流                 
                    img.Save(path);//保存            }            catch (Exception ex)
                {
                    string aa = ex.Message;
                }
                finally
                {
                    res.Close();
                }
                return img;
            }
      

  8.   


    Queue qu = new Queue();//创建队列
            //下载图片回来
            private void button2_Click(object sender, EventArgs e)
            {            Thread th1 = new Thread(Reader);//将数据读取到队列
                th1.Start();
                Delay(1000);
                Queue();
            }        //开启线程执行下载
            public void Queue()
            {
                if (qu.Count!= 0)//如果集合里有数据
                {             //这里如何开10个线程来循环下载队列里的数据
                }        }
      

  9.   

    for循环10次,开10个线程
    每个线程里都执行同一个方法while(true)
    {
    lock(L)
    {
    if(qu.Count>0)
    {
    取出qu[0]先放局部变量里
    qu.removeAt(0);
    }
    else
    {
    break;
    }
    }
    开始下载
    }
      

  10.   

    L是全局静态变量,可以是随便什么类型
    一般都定义成object L=new object();这样被lock(L)包住的代码段,每次只能有1个线程执行,其他线程会暂时阻塞
    但是这个操作很快,所以不会很耗时间,真正耗时间的应该是下载.
      

  11.   


     Queue qu = new Queue();//创建队列
            //下载图片回来
            private void button2_Click(object sender, EventArgs e)
            {            Thread th1 = new Thread(Reader);//将数据读取到队列
                th1.Start();
                Delay(1000);
                Queue();
            }        //开启线程执行下载
            public void Queue()
            {
                //object L = new object();             //for(int i=1;i<=10;i++)
                 //{
                 //    if (qu.Count > 0)
                 //    {
                         
                 //        Thread t = new Thread();
                 //        t.Start();
                 //    }
                 //}
            }
    现在qu里的数据格式为
    222#5#7#http://www.aa.com/1.jpg#http://www.aa.com/1.html