7,763
社区成员
发帖
与我相关
我的任务
分享
using System;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
for (var i = 0; i < 30; i++)
Test(i);
Console.WriteLine("................按任意键结束");
Console.ReadKey();
}
static async void Test(int i)
{
var r = await 加100000(i);
Console.WriteLine($"输入:{i}, 输出:{r}");
}
static Random rnd = new Random();
static async Task<int> 加100000(int x)
{
var d = rnd.Next(3000, 5000);
await Task.Delay(d); //模拟耗时操作
return x + 100000;
}
}
}
因为 .net 系统线程池会自动化地根据当前系统资源情况而调度——延迟——发起并发任务,所以你根本不需要自己写什么控制任务的代码,根本不用什么“队列”。因为 .net 系统线程池本身就是队列,而且它本身就把线程执行任务所需要的内存中的状态对象数据维持着(根本不需要什么“字符串)。
因此,实际上根本不用扯到什么“队列”,在 .net 上你用涉及到系统线程池的各种高级别的框架(例如PLinq)来编程,你基本上就不用考虑什么队列了。纠结队列时我们可以看作是 java 程序员或者一些 c 语言初学者,这些人才会特别喜欢底层的概念。using System;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
for (var i = 0; i < 30; i++)
Test(i);
Console.WriteLine("................按任意键结束");
Console.ReadKey();
}
static int 执行中数量;
static object lockflag = new object();
static event Action<int> 有任务结束;
static async void Test(int i)
{
lock (lockflag)
{
if (执行中数量 >= 3)
{
Action<int> proc = null;
proc = new Action<int>(x =>
{
有任务结束 -= proc;
Test(i);
});
有任务结束 += proc;
return;
}
else
执行中数量++;
}
var r = await 加100000(i);
Console.WriteLine($"输入:{i}, 输出:{r}");
lock (lockflag)
{
Console.WriteLine($"--------输入:{i} 结束后执行中数量为:{执行中数量}");
执行中数量--;
}
if (有任务结束 != null)
有任务结束(i);
}
static Random rnd = new Random();
static async Task<int> 加100000(int x)
{
var d = rnd.Next(3000, 5000);
await Task.Delay(d); //模拟耗时操作
return x + 100000;
}
}
}
这里,假设任务是要把输入的 i 加上 100000 然后输出,主程序快速发起了30个并发任务,但是此 Test 方法要求最多同时执行3个任务,其它的排队等候。你可以运行这个例子,然后回答你自己的问题:
当产生了并发任务之后,首先进入第一个 lock 管理区域,此时判断如果运行的并发任务数量>=3的时候,则向事件监听队列注册监听,然后就立刻结束了。当事件发生(有其它任务结束),则从事件队列中首先注销监听,然后重新执行本任务(重新开始判断是否并发任务数量>=3)。否则,它就立刻把并发任务数量++。注意这两个动作是在 lock 管理范围中的,同一时间只有一个线程能够执行这个范围中的代码,所以这就保证不会产生混乱控制。
15或者20年前,像java的语言比较原始,远比当初的 .net 更加原始,所有一大堆垃圾java书都是抄袭30年前、40年前的c、unix书籍上的一些概念。所谓“队列”就是一个比较容易庸俗化的概念。许多程序貌似用了“队列”这个词儿给自己贴金,而实际上还是顺序阻塞的思路,那些书上的“队列”就是运行时低效的、代码繁琐的东西。所以这里关键是用精炼的代码,用优雅的.net机制来写高效率的代码,所以你提的几个问题很好,你没有纠结“队列”这个词儿而是问到了关键的细节上! if (有任务结束 != null)
有任务结束(i);
改为代码 if (有任务结束 != null)
{
var cnt = 0;
foreach (Action<int> proc in 有任务结束.GetInvocationList())
{
proc(i);
if (++cnt >= 3)
break;
}
}
这里仅仅通知最多3个宿主,而不是把事件通知给所有的监听宿主。
这里编程时就是围绕“数据的”,但是这是什么数据?这种数据是不是队列?这是高级的数据概念,是解决实际应用的各种实用框架,不是重复一个简单的数据结构。 event Action<int> 有任务结束
声明了一个多播委托列表,它是不是数据?.net 线程池机制本身所管理的内部数据结构是不是数据?
唯一可以挑出来点儿的,也就是说这两个数据(多播委托、线程池内部机制)没有将这些数据序列化/反序列化到你自己的文件中而已。人家的现成的管理机制高速地管理大量排队信息,能不能只想着自己发明那些简单的博客上的最底层的简单“队列”概念而不认识 .net 框架中许多高级别的自动化流水处理任务调度的功能。