110,537
社区成员
发帖
与我相关
我的任务
分享
static void proc(int data)
{
Console.WriteLine("判断数据 {0}", data);
lock (lst)
{
if (lst.Contains(data))
return;
lst.Add(data);
if (lst.Count >= 6)
lst.RemoveRange(0, 3);
Thread.Sleep(new Random().Next(0, 1000)); //模拟耗时操作
Console.WriteLine("\t\t\t返回为 {0}", data);
}
}
这时候就会发现整个处理过程多用了很多时间才完成。
实际上纠结具体的某个语句、某个数据结构,并不会在这里真正提高多少效率。问题主要出在滥用同步加锁范围、或者就是滥用“队列概念”上了。如果你在线程中尽可能少地代码、短的代码才放在同步 lock{.....} 中间,而不是长时间同步,则能保证更高的并发执行效率。否则纠结再高达上的数据结构名词儿,也不会提高什么效率。 if (lst.Count >= 6)
lst.RemoveRange(0, 3);
其实差别也并不大。using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(h => proc(1));
ThreadPool.QueueUserWorkItem(h => proc(2));
ThreadPool.QueueUserWorkItem(h => proc(3));
ThreadPool.QueueUserWorkItem(h => proc(4));
ThreadPool.QueueUserWorkItem(h => proc(2));
ThreadPool.QueueUserWorkItem(h => proc(5));
ThreadPool.QueueUserWorkItem(h => proc(3));
ThreadPool.QueueUserWorkItem(h => proc(1));
ThreadPool.QueueUserWorkItem(h => proc(2));
ThreadPool.QueueUserWorkItem(h => proc(5));
ThreadPool.QueueUserWorkItem(h => proc(3));
ThreadPool.QueueUserWorkItem(h => proc(6));
ThreadPool.QueueUserWorkItem(h => proc(3));
ThreadPool.QueueUserWorkItem(h => proc(4));
ThreadPool.QueueUserWorkItem(h => proc(2));
ThreadPool.QueueUserWorkItem(h => proc(5));
ThreadPool.QueueUserWorkItem(h => proc(6));
ThreadPool.QueueUserWorkItem(h => proc(3));
ThreadPool.QueueUserWorkItem(h => proc(4));
Console.WriteLine("....................按任意键结束");
Console.ReadKey();
}
private static List<int> lst = new List<int>();
static void proc(int data)
{
Console.WriteLine("判断数据 {0}", data);
lock (lst)
{
if (lst.Contains(data))
return;
lst.Add(data);
if (lst.Count >= 6)
lst.RemoveRange(0, 3);
}
Thread.Sleep(new Random().Next(0, 1000)); //模拟耗时操作
Console.WriteLine("\t\t\t返回为 {0}", data);
}
}
}
这里,以并发多线程方式调用 proc(data) 来处理多个数据,使用 lst 来保存缓冲重复数据,并且当它长度为6 时截断前边3个单元(先入先出)。
你可以看到,这里使用 lock 来同步线程处理中的查重部分(因为这部分如果并发执行则会有冲突),而一旦查重结束则后边的耗时操作就并发执行了(从打印结果的”乱“其实就能看出这里恰好达到了并发处理耗时操作的目的)。