多线程应用场合?
我看资料说是以下情况可能会用到多线程
1.程序需要同时执行两个或多个任务
2.程序要等待某事件的发生,例如用户输入、文件操作、网络操作、搜索等
3.后台程序
大家能否具体举几个例子?(有代码更好理解)
[解决办法]
因为操作系统按照线程调度CPU,所以在多处理器环境下,多线程可以利用处理器并行提高速度。
其余的场合基本如你所说,一个是逻辑上的并发,一个是延迟隐藏(比如网络、IO等等),还有就是防止UI阻塞。
[解决办法]
多线程用于后台操作,可以充分发挥多核CPU的性能。
但多线程不能滥用。
多线程是魔鬼,很多意想不到匪夷所思的bug都会在多线程环境下产生。
所以msdn里每介绍一个对象都会声明它在多线程下的特性。
[解决办法]
比如说程序要提取网页中信息,首先要下载网页地址的源代码,然后分析,那么在下载网页的时候就可能因为网速等各种原因卡住,这时候就应该用多线程,全都边下载边分析
[解决办法]
服务器监听客户端连接时
Task.Factory.StartNew((hostinfo) =>
{
var ipe = hostinfo as IPEndPoint;
var listner = new TcpListener(ipe);
listner.Start();
while (this.flagServer)
{
if (listner.Pending())
{
var client = listner.AcceptTcpClient();
this.DisplayMessage(string.Format("{0} connecting", client.Client.RemoteEndPoint));
var ope = new UserOperation(client);
ope.MessageReceived += new EventHandler<UserOperation.MessageEventArgs>(ope_MessageReceived);
ope.UserLogined += new EventHandler(ope_UserLogined);
ope.UserLogouted += new EventHandler(ope_UserLogouted);
lock (this.listUser)
{
this.listUser.Add(ope);
}
ope.Start();
}
Thread.Sleep(1);
}
listner.Stop();
}, lep);
客户端接等待接收数据时
Task.Factory.StartNew((obj) =>
{
var ope = obj as UserOperation;
var buffer = new byte[BufferSize];
var ss = new List<byte>();
try
{
using (var strm = ope.client.GetStream())
{
var search = 0;
var foundCR = -1;
var found = 0;
while (this.flagLoop)
{
if (strm.DataAvailable)
{
var readsize = strm.Read(buffer, 0, BufferSize);
ss.AddRange(buffer.Where<byte>((bt, idx) => idx < readsize));
}
for (var idx = search; idx < ss.Count; idx++)
{
if (ss[idx] == 0x0d)
{
foundCR = idx;
}
if (ss[idx] == 0x0a)
{
if (idx == foundCR + 1)
{
found = idx;
break;
}
}
}
if (found > 0)
{
var message = Encoding.Default.GetString(ss.Where<byte>((bt, idx) => idx < found - 1).ToArray<byte>());
this.ProcessMessage(message);
ss.RemoveRange(0, found + 1);
foundCR = -1;
found = 0;
search = 0;
}
lock (this.messageQueue)
{
if (this.messageQueue.Count > 0)
{
var top = this.messageQueue.Dequeue();
var send = Encoding.Default.GetBytes(top + "\r\n");
strm.Write(send, 0, send.Length);
}
}
Thread.Sleep(1);
}
}
}
finally
{
ope.client.Close();
}
}, this);
}
[解决办法]
给你贴一个实际的例子。比如说我们要更新服务器上的系统,这个系统往往有(比如说)800M,有1万多个文件。通常流程是这样的:
1. 采取文件上传工具将文件上传到服务器的文件夹 x 下面。
2. 立刻停下服务器进程。
3. 从文件夹 x 将那些修改过的文件自动更新到之前真正执行的服务器程序的文件夹下。
4. 重新启动服务器进程。
这个过程,要求第3运行得尽可能快速和准确。如果是比较“悲催”地操作,可能这一步需要执行20分钟,但是如果你仅仅复制设计修改过的文件,并且提高并发,通常则可以在1分钟内就执行完毕。可见这种差别是巨大的。
下面这个程序就演示了这样的复制过程:
/// <summary>
/// 复制文件夹下所有md5不一致的文件。
/// </summary>
/// <param name="source">源文件夹</param>
/// <param name="target">目标文件夹</param>
/// <param name="excludes">排除符合这些后缀的文件(避免被覆盖)</param>
/// <param name="deleteSameFiles">同时删除相同的目标文件</param>
private static void CopyAll(DirectoryInfo source, DirectoryInfo target, string[] excludes = null, bool deleteSameFiles = false)
{
Create(target);
var manuals = new List<ManualResetEvent>();
var targetPath = target.FullName;
var subs = source.GetDirectories();
for (var i = 0; i < subs.Length; i++)
{
var source1 = subs[i];
var target1 = new DirectoryInfo(Path.Combine(targetPath, source1.Name));
var m = new ManualResetEvent(false);
manuals.Add(m);
new Thread(() =>
{
CopyAll(source1, target1, excludes);
m.Set();
}).Start();
}
while (manuals.Count > 0)
{
var ms = manuals.Take(64).ToArray();
manuals = manuals.Skip(64).ToList();
WaitHandle.WaitAll(ms);
} //所有子目录全都拷贝完毕,才拷贝当前目录
lock (Console.Out)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(target.FullName);
}
foreach (var f in source.EnumerateFiles().Where(x => excludes == null
[解决办法]
!excludes.Contains(x.Extension.ToLower())))
{
var m = new ManualResetEvent(false);
manuals.Add(m);
new Thread(() =>
{
CopyFile(targetPath, f, deleteSameFiles);
m.Set();
}).Start();
}
while (manuals.Count > 0)
{
var ms = manuals.Take(64).ToArray();
manuals = manuals.Skip(64).ToList();
WaitHandle.WaitAll(ms);
}
}
private static void CopyFile(string targetPath, FileInfo f, bool deleteSameFile)
{
var m1 = MD5(File.ReadAllBytes(f.FullName));
var tar = Path.Combine(targetPath, f.Name);
if (File.Exists(tar) && MD5相等(m1, MD5(File.ReadAllBytes(tar))))
{
if (deleteSameFile)
{
lock (Console.Out)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(tar);
}
File.Delete(tar);
}
}
else
{
lock (Console.Out)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(tar);
}
f.CopyTo(tar, true);
}
}
private static void Create(DirectoryInfo target)
{
if (target.Exists)
return;
var parent = target.Parent;
Create(parent);
target.Create();
}
private static bool MD5相等(byte[] m1, byte[] m2)
{
for (var i = 0; i < m1.Length; i++)
if (m1[i] != m2[i])
return false;
return true;
}
public static byte[] MD5(byte[] data)
{
var mac = new MD5CryptoServiceProvider();
return mac.ComputeHash(data);
}