正常点的解决方法就是额外加一个字段用于记录当前行的处理状态
比如初始值是0,处理中是1,完成是2,失败代码是100开头的自定义序列丢出去若干个exe,每个exe分20个线程跑,每次每个exe取一千或若干条记录,同时更新他们的处理状态为处理中,干完以后批量更新处理完成不过你那才几十万条记录,就单个exe不加字段直接运行估计也完事了,写一点本地文件做log,标记一下处理到第几行以及失败的主键值
比如初始值是0,处理中是1,完成是2,失败代码是100开头的自定义序列丢出去若干个exe,每个exe分20个线程跑,每次每个exe取一千或若干条记录,同时更新他们的处理状态为处理中,干完以后批量更新处理完成不过你那才几十万条记录,就单个exe不加字段直接运行估计也完事了,写一点本地文件做log,标记一下处理到第几行以及失败的主键值
当然需要一个额外的线程负责调度那些下载的线程.都让主线程去做,不怕阻塞UI影响显示么?
如果是SQL SERVER数据库,有TOP关键字,可以只读取一部分数据.其他数据库暂时不知道怎么办,几十万不多,都读出来算了.2,下载完一条就去数据库删除一条吗?
也可以都下载完批量删除,省事.3,如何才能保证多线程操作时不会撞车,如同一条数据被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个线程来慢慢下载这些任务。现在就是卡在如何让线程执行完一个任务以后,不关闭,再去执行下一个任务。从来没搞过这样的,一点经验都没有
先开一个线程,然后执行查询,查询后结果ADD进LIST
然后在这个线程里再开10个线程,执行同一个方法,就是去LIST里取一条数据,取出一条,就REMOVE一条,这样可以避免重复任务
当然写入LIST,读取LIST和删除LIST,这些都要加锁,避免同时进行出错之后就简单了,既然每个线程都取到了一个不同的任务,就开始执行吧
执行完回到开始(用循环),再去取任务,再执行,直到队列里已经没有任务了,退出
最好事先copy个副本,方便之后在原始datatable里记录些信息或用它来更新数据库.
1.可以一次性都查出来,然后就一直处理.
2.也可以查100条,开10个线程,然后等待,等线程都退出了,再次查100条,再开10个线程
3.也可以完全分开,先查100条,然后开10个线程,然后不断的去看队列里还剩多少任务,不足20了,就再查100条ADD进去
能不能具体点,比如锁如何加,LIST如何操作等等...
目前已经实现了读取数据库添加到队列,不知道如何使用线程来操作这些队列具体代码:
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;
}
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个线程来循环下载队列里的数据
} }
每个线程里都执行同一个方法while(true)
{
lock(L)
{
if(qu.Count>0)
{
取出qu[0]先放局部变量里
qu.removeAt(0);
}
else
{
break;
}
}
开始下载
}
一般都定义成object L=new object();这样被lock(L)包住的代码段,每次只能有1个线程执行,其他线程会暂时阻塞
但是这个操作很快,所以不会很耗时间,真正耗时间的应该是下载.
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