我有一个应用程序,可以同时运行任务。我们在这里设定
MaxDegreeOfParallelism=4
,这意味着在任何时候最多同时运行4个任务。在这种情况下,我只有4个频道可用。否则是异常
无法获得频道
将被抛出。
每个任务都有一个OutboundDial
的实例,所以最多只有4个实例。
public class OutboundDial
{
private ChannelResource m_ChannelResource;
private VoiceResource m_VoiceResource;
private TelephonyServer m_TelephonyServer;
private AppointmentReminderResult m_Result = new AppointmentReminderResult();
public OutboundDial(TelephonyServer telephonyServer)
{
m_TelephonyServer = telephonyServer;
}
internal void RunScript(AppointmentReminder callData)
{
try
{
try
{
m_ChannelResource = m_TelephonyServer.GetChannel();
m_VoiceResource = m_ChannelResource.VoiceResource;
}
catch (Exception ex)
{
Console.WriteLine("Could not get channel: {0}",ex.StackTrace);
return;
}
// a long running process of I/O bound operation
生产者 - 消费者队列
public static BufferBlock<AppointmentReminder> m_Queue =
new BufferBlock<AppointmentReminder>(new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = 4});
BufferBlock是TPL类。 TelephontServer最初初始化。
public static TelephonyServer ts;
ts = new TelephonyServer(sIpaddress, "username", "password");
在消费者部分,我们有:
static async Task Consumer()
{
try
{
while (await m_Queue.OutputAvailableAsync())
{
m_Queue.TryReceive(4, ts); // MaxDegreeOfParallelism = 4
}
}
TryReceive
是一种扩展方法。
public static void TryReceive<T>(this BufferBlock<T> bufferBlock, int count, TelephonyServer ts) where T : AppointmentReminder
{
try
{
for (var i = 0; i < count; i++)
{
T item;
if (bufferBlock.TryReceive(out item))
{
Task t = Task.Run(() =>
{
OutboundDial d = new OutboundDial(ts);
d.RunScript<T>((T)item);
});
}
else
{
break;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
}
我的问题:我在生产者部分的队列中添加了10个项目,并在构造函数中设置了一个断点。
我发现代码在构造函数中运行了10次,然后运行了10次RunScript
,这表示10个任务一起运行而不是4个。但我只想要4(MaxDegreeOfParallelism)。因此,我没有足够的频道可用,抛出异常。
为什么在我的扩展方法中并发运行不起作用?
答案 0 :(得分:1)
BufferBlock
并未真正执行任何操作,因此指定其MaxDegreeOfParallelism
没有意义。它的作用只是因为ExecutionDataflowBlockOptions
继承自DataflowBlockOptions
,这是BufferBlock
构造函数所期望的。
你的Consumer()
执行此操作:最多需要4个项目并执行它们,最多需要4个项目并执行它们,最多需要4项并执行它们等等。因为你永远不会等待那些要完成的执行,你实际上并没有以这种方式限制并行度。
如果您想将并行度限制为4,则可以使用ActionBlock
,而不是BufferBlock
和Consumer()
的组合:
new ActionBlock<AppointmentReminder>(
reminder => new OutboundDial(ts).RunScript(reminder),
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4});
这样做是为每个提醒执行lambda,但最多同时执行4个,这似乎是你要求的。虽然我不确定你需要什么,因为你似乎不会在使用后释放(处置)频道,用于下一次提醒。
答案 1 :(得分:0)
目前还不清楚问题出在哪里,但似乎不是在方法之后调用cinstructor。 我建议你将构造函数代码更改为:
public OutboundDial(TelephonyServer telephonyServer)
{
m_TelephonyServer = telephonyServer;
Console.WriteLine(m_Telephonyserver);
}
然后你会确定构造函数是完整的。
此外,在RunScript中的每一行之后添加一些Console.WriteLine和有用的信息 - 然后您将看到错误的来源。