编程不能死记硬背死记硬背,要靠多实践操作(图)
优采云 发布时间: 2021-08-24 22:10编程不能死记硬背死记硬背,要靠多实践操作(图)
编程不能死记硬背,要靠实践。
现在互联网越来越发达,共享一个文件就是这么简单。尤其是搭配电骡、迅雷等下载软件,功能更强大。如果你想从网上下载几个G大小的文件,真的不费吹灰之力。好了,废话太多了,直接进入今天的话题。
实现像迅雷一样的多线程下载,核心问题是厘清多线程的概念以及如何实现。
当然,本文技术含量很低,请直接绕道。
多线程相对单线程。详情请参考百度百科中的解释:
每个程序运行一个基本的主线程,用于处理界面绘制、人机交互、后台处理等过程。因此,如果是单线程程序中的耗时操作,主界面会很卡,甚至无法工作。所以,不管喜不喜欢,最好不要用主线程来打理一切,否则很难给用户带来舒适的客户体验。
那么如何在C#中实现多线程?
下面我们来实现一个最简单的多线程例子;
为了演示方便,我们新建一个winform工程,命名为MultiThreadDemo。
首先创建一个足以让你的程序卡住的方法函数:
private void Display()
{
while (true)
textBox1.Text = new Random().NextDouble().ToString();
}
然后再调用button1,发现真的卡住了。谁让你把无限循环留给主线程去做的。画个图算了,没时间回复了。
using System.Threading;
接下来,在button1中添加代码并为他创建一个线程。我们称这个线程为“UiThread”来处理显示。
查看代码
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(Display);//创建一个线程
thread.Start();
// Display();
}
你要是着急跑,肯定会回来骂我的,何乐而不为呢?是不是会提示:“线程间操作无效:创建控件“textBox1”的线程从不访问它。”。因为主线程和你创建的线程是两个不相关的线程,两个陌生人怎么处理?也就是你的UiThread在没有主线程同意的情况下调用textBox1,其他人会让你这么做吗?
因此,为了处理他们工作不协调的问题,特意强行取消了线程警告。在构造函数中加一句:
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;//加上这句就不会警告了
}
这样一个简单的多线程程序就诞生了。但是有时候有很多代码需要用到delegate,又不想单独创建一个函数,可以这样做:
查看代码
private void button1_Click(object sender, EventArgs e)
{
ThreadStart threadStart = new ThreadStart(delegate { Display(); });//创建一个委托,这样可以调用任意参数的函数了,甚至是零星的代码都可以
Thread thread = new Thread(threadStart);
thread.Start();
}
但是,不建议这样做。在线程上是不安全的,很有可能导致程序崩溃。
通过上面的练习,我们知道创建一个线程可以做更多的事情。同样,如果我们多创建几个线程,我们做的不是更多吗?这是必须的。
接下来正式走进我们今天的话题:多线程采集
如果要多线程采集,必须先解决单次下载。
using System.Net;
using System.IO;
查看代码
///
/// 转载请加上本人博客链接
///
///
///
static void Request(RichTextBox richtextBox,int i)
{
richtextBox.AppendText(string.Format("线程{0}开始接收\n", Thread.CurrentThread.Name));
ServicePointManager.DefaultConnectionLimit = 1000;
HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(string.Format("http://news.cnblogs.com/n/{0}/", (int)i));//这里的i最嗨是158100到158999,符合博客园url规则才能采集到
StreamWriter sw = File.CreateText(string.Format(Environment.CurrentDirectory + "\\{0}.htm", i));
try
{
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
Stream stream = httpWebResponse.GetResponseStream();
StreamReader sr = new StreamReader(stream);
string html = sr.ReadToEnd();
richtextBox.AppendText(string.Format(Thread.CurrentThread.Name + "接收完毕"));
sw.Write(html);
sw.Close();
}
catch
{
richtextBox.AppendText(string.Format("线程{0}不存在此地址,跳过\n", Thread.CurrentThread.Name));
sw.Write(string.Format("线程{0}不存在此地址,跳过\n", Thread.CurrentThread.Name));
return;
}
}
然后调用button2
查看代码
private void button2_Click(object sender, EventArgs e)
{
ThreadStart threadStart = new ThreadStart(delegate { Request(richTextBox1, 158100); });//创建一个委托,这样可以调用任意参数的函数了,甚至是零星的代码都可以
Thread thread = new Thread(threadStart);
thread.Start();
}
这样,一个采集就完成了。
想要像优采云采集那样,在现在的层次自然是做不到的。至少应该制作批次采集。无非是使用多线程。
查看代码
///
/// 转载请加上本人博客链接
///
///
///
static void Request(RichTextBox richtextBox,int i)
{
richtextBox.AppendText(string.Format("线程{0}开始接收\n", Thread.CurrentThread.Name));
ServicePointManager.DefaultConnectionLimit = 1000;
HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(string.Format("http://news.cnblogs.com/n/{0}/", (int)i));//这里的i最嗨是158100到158999,符合博客园url规则才能采集到
try
{
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
Stream stream = httpWebResponse.GetResponseStream();
StreamReader sr = new StreamReader(stream);
string html = sr.ReadToEnd();
richtextBox.AppendText(string.Format(Thread.CurrentThread.Name + "接收完毕\n"));
StreamWriter sw = File.CreateText(string.Format(Environment.CurrentDirectory + "\\{0}.htm", i));
sw.Write(html);
sw.Close();
}
catch
{
richtextBox.AppendText(string.Format("线程{0}不存在此地址,跳过\n", Thread.CurrentThread.Name));
}
}
private void button2_Click(object sender, EventArgs e)
{
Thread.CurrentThread.Name = "主线程";
Thread[] threads = new Thread[51];
DateTime endTime = DateTime.Now;
DateTime startTime = DateTime.Now;
TimeSpan timeSpan = endTime - startTime;
string span = timeSpan.TotalSeconds.ToString();
startTime = DateTime.Now;
Mutex mt = new Mutex();
mt.WaitOne();
for (int i = 158300; i >158250; i--)
{
threads[158300 - i] = new Thread(new ParameterizedThreadStart(delegate { Request(richTextBox1, i); }));
threads[158300 - i].Name = "线程" + (i).ToString(); ;
threads[158300 - i].Start();
}
mt.ReleaseMutex();
endTime = DateTime.Now;
timeSpan = endTime - startTime;
span = timeSpan.TotalSeconds.ToString();
richTextBox1.AppendText(string.Format("多线程接受的话共花费了{0}秒钟\n", span));
}
多线程采集 已完成。其实这篇文章主要是关于创建线程的话题,技术含量比较低,给刚入门的朋友练习一下吧!
教程每天都会更新,请继续关注。
///************************************************ ****************