考虑一个包含大量需要处理的作业的队列.队列限制一次只能获得1个工作,无法知道有多少工作.这些作业需要10秒才能完成,并且需要大量等待来自Web服务的响应,因此不受CPU限制.
如果我使用这样的东西
while (true)
{
var job = Queue.PopJob();
if (job == null)
break;
Task.Factory.StartNew(job.Execute);
}
Run Code Online (Sandbox Code Playgroud)
然后,它会以比完成它们更快的速度从队列中快速弹出作业,耗尽内存并堕落.> <
我不能使用(我不认为)ParallelOptions.MaxDegreeOfParallelism因为我不能使用Parallel.Invoke或Parallel.ForEach
我找到了3个替代方案
用.替换Task.Factory.StartNew
Task task = new Task(job.Execute,TaskCreationOptions.LongRunning)
task.Start();
Run Code Online (Sandbox Code Playgroud)
这似乎在某种程度上解决了这个问题,但我不清楚这是做什么的,如果这是最好的方法.
创建一个限制并发度的自定义任务调度程序
使用类似BlockingCollection的东西在启动时将作业添加到集合中,并在完成时删除以限制可以运行的编号.
#1我必须相信自己做出正确的决定,#2 /#3我必须计算出自己可以运行的最大数量的任务.
我是否理解正确 - 这是更好的方式,还是有另一种方式?
编辑 - 这是我从下面的答案,生产者 - 消费者模式中得出的结果.
除了整体吞吐量目标不是要比可以处理的更快地使作业出列并且没有多个线程轮询队列(这里没有显示但是这是非阻塞的操作并且如果从多个地方以高频率轮询将导致巨大的交易成本) .
// BlockingCollection<>(1) will block if try to add more than 1 job to queue (no
// point in being greedy!), or is empty on take.
var BlockingCollection<Job> jobs = …Run Code Online (Sandbox Code Playgroud) 最近在接受采访时,我得到了这个问题.
问:您是否编写过多线程应用程序?
答:是的
问:关心解释更多?
答:我用Tasks(任务并行库)来执行一些任务waiting for some info from internet while loading UI.这提高了我的应用程序可用性.
问:但是,您是否已经使用过TPL手段来编写multithreaded应用程序?
我:(不知道该说些什么1)
那么,什么是多线程应用程序呢?它与使用不同Tasks吗?
c# multithreading .net-4.0 multitasking task-parallel-library
我需要实现一个库来请求vk.com API.问题是API每秒只支持3个请求.我想让API异步.
重要: API应支持从多个线程安全访问.
我的想法是实现一个名为throttler的类,它允许不超过3个请求/秒并延迟其他请求.
接口是下一个:
public interface IThrottler : IDisposable
{
Task<TResult> Throttle<TResult>(Func<Task<TResult>> task);
}
Run Code Online (Sandbox Code Playgroud)
用法就像
var audio = await throttler.Throttle(() => api.MyAudio());
var messages = await throttler.Throttle(() => api.ReadMessages());
var audioLyrics = await throttler.Throttle(() => api.AudioLyrics(audioId));
/// Here should be delay because 3 requests executed
var photo = await throttler.Throttle(() => api.MyPhoto());
Run Code Online (Sandbox Code Playgroud)
如何实施throttler?
目前我将其实现为由后台线程处理的队列.
public Task<TResult> Throttle<TResult>(Func<Task<TResult>> task)
{
/// TaskRequest has method Run() to run task
/// TaskRequest uses TaskCompletionSource to provide new task
/// which is …Run Code Online (Sandbox Code Playgroud) 我在另一个答案中找到了这个类.在.NET中管理单独(单个)线程上的任务队列的最佳方法.
我想尝试一下,但语法对我来说有点奇怪.试图启动一个返回单个int的虚拟任务.我无法编译,不知道语法问题是什么.
m_TaskQueue.Enqueue<int>(
() => { return 1; }
);
Run Code Online (Sandbox Code Playgroud)
编译错误:
无法将lambda表达式转换为委托类型,
System.Func<System.Threading.Tasks.Task<int>>因为块中的某些返回类型不能隐式转换为委托返回类型
来自其他答案的课程:
public class TaskQueue
{
private SemaphoreSlim semaphore;
public TaskQueue()
{
semaphore = new SemaphoreSlim(1);
}
public async Task<T> Enqueue<T>(Func<Task<T>> taskGenerator)
{
await semaphore.WaitAsync();
try
{
return await taskGenerator();
}
finally
{
semaphore.Release();
}
}
public async Task Enqueue(Func<Task> taskGenerator)
{
await semaphore.WaitAsync();
try
{
await taskGenerator();
}
finally
{
semaphore.Release();
}
}
}
Run Code Online (Sandbox Code Playgroud)