1
//要执行的业务是从阿里云上下载将近40000条的音频到本地,单条下载忒慢,就想采用多线程,分配了二十个线程同时下载,省了很大部分的时间
class Program
2 {
3
4 static void Main(string[] args) {
5 string sql = "select en_audio,us_audio from t_audio LIMIT 198 ";
6 MySqlDataReader mySqlDataReader = DBHelper.ExecuteReader(sql);
7 List<String> sList = new List<String>();
8 sList.Add("https://qutifen-qudao.oss-cn-beijing.aliyuncs.com/mfg/audio/v3/1abacus_en.ogg");
9 sList.Add("https://qutifen-qudao.oss-cn-beijing.aliyuncs.com/mfg/audio/v3/2abacus_en.ogg");
10 if (mySqlDataReader.HasRows)
11 {
12 while (mySqlDataReader.Read())
13 {
14 sList.Add(mySqlDataReader.GetString(0));
15 sList.Add(mySqlDataReader.GetString(1));
16 }
17 }
18 Console.WriteLine(sList.Count);
19 Stopwatch stopwatch = new Stopwatch();
20 stopwatch.Start();
21 ThreadStart(sList);
22 WaitHandle.WaitAll(waits); //监听wait里面的所有的线程都已经set了 才执行下面的代码,否则一直在这里等待
23 stopwatch.Stop();
24 Console.WriteLine($"耗时{stopwatch.ElapsedMilliseconds}毫秒");
25 Console.ReadKey();
26
27
28 }
29 static Thread[] threads = new Thread[20];
30 static WaitHandle[] waits = new WaitHandle[20];
31 public static void ThreadStart(List<String> nums) {
//分配线程
32 for (int i=0;i<20;i++) {
33 threads[i] = new Thread(DownLoadFile);
34 waits[i] = new AutoResetEvent(false);
35
36 }
//为每个线程分配要执行的数据并开始执行
37 for (int i = 0; i < 20; i++)
38 {
39 if (i== threads.Length-1) {
40 var retult = nums.Skip(nums.Count / 20 * i).Take(nums.Count- nums.Count / 20*i).ToList();
41 threads[i].Start(new Objpt()
42 {
43 sList = retult,
44 WaitHandle = waits[i],
45 ThreadIndex = i
46 });
47 }
48 else {
49 var retult= nums.Skip(nums.Count / 20 * i).Take(nums.Count / 20).ToList();
50 threads[i].Start(new Objpt() {
51 sList= retult,
52 WaitHandle=waits[i],
53 ThreadIndex=i
54 });
55 }
56
57 }
58 }
59
60 public static void DownLoadFile(Object obj)
61 {
62 int count = 0;
63 Objpt optObj = (obj as Objpt);
64 var sList = optObj.sList;
65 Console.WriteLine($"线程{optObj.ThreadIndex}开始了");
66 foreach (var url in sList)
67 {
68 try
69 {
70 count++;
71 var arrs = url.Split('/');
72 WebRequest request = WebRequest.Create(url);
73 HttpWebResponse res = (HttpWebResponse)request.GetResponse();
74 WebResponse response = request.GetResponse();
75 if (res.StatusCode.ToString() == "OK")
76 {
77 Stream responseStream = response.GetResponseStream();
78 using (FileStream fsWrite = new FileStream($"F:/Audio/v4/{arrs[arrs.Length - 2]}/{arrs[arrs.Length - 1]}", FileMode.OpenOrCreate, FileAccess.Write))
79 {
80 byte[] buffer = new byte[response.ContentLength];
81 while (true)
82 {
83 ////返回本次实际读取到的字节数
84 int r = responseStream.Read(buffer, 0, buffer.Length);
85 if (r == 0)
86 {
87 break;
88 }
89 fsWrite.Write(buffer, 0, r);///写入
90
91 }
92 }
93 }
94 //if (count % 20 == 0 || count == sList.Count)
95 //{
96 // Console.WriteLine($"线程{optObj.ThreadIndex}已处理个数:{count}");
97 //}
98
99 }
100 catch (Exception ex)
101 {
102 string strErrorLogFile = System.AppDomain.CurrentDomain.BaseDirectory + $"\\{optObj.ThreadIndex}ErrorLog.log";
103 if (!System.IO.File.Exists(strErrorLogFile))
104 System.IO.File.WriteAllText(strErrorLogFile, "//系统错误日志记录文件\r\n");
105 object objSql ="线程"+ optObj.ThreadIndex.ToString()+ ex.Message;
106 System.IO.File.AppendAllText(strErrorLogFile, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\t" + objSql.ToString() + url + "\r\n");
107
108 }
109
110 }
111 Console.WriteLine($"线程{optObj.ThreadIndex}结束");
112 (optObj.WaitHandle as AutoResetEvent).Set(); //set方法是当某个线程结束起做个标记的作用
113 }
114 }
115
116 public class Objpt {
117 public List<String> sList { get; set; }
118 public WaitHandle WaitHandle { get; set; }
119 public int ThreadIndex { get; set; }
120
121 }