具有异步顺序任务的TaskScheduler C#

具有异步顺序任务的TaskScheduler C#,c#,c#-4.0,C#,C# 4.0,我正在异步执行一些.py脚本。一个脚本执行大约需要30秒。在两三秒钟的时间跨度内,可能会选择两个或更多脚本。目标是拥有一个调度器,它收集所有任务并逐个执行。应包括FIFO功能。 我尝试了以下代码,只是为了尝试queuedTaskScheduler的功能,但即使这样也不起作用 QueuedTaskScheduler queueScheduler; private TaskScheduler ts_priority1; int pos = 0; public Form1()

我正在异步执行一些.py脚本。一个脚本执行大约需要30秒。在两三秒钟的时间跨度内,可能会选择两个或更多脚本。目标是拥有一个调度器,它收集所有任务并逐个执行。应包括FIFO功能。 我尝试了以下代码,只是为了尝试queuedTaskScheduler的功能,但即使这样也不起作用

QueuedTaskScheduler queueScheduler;
private TaskScheduler ts_priority1;
int pos = 0;
        public Form1()
    {
        InitializeComponent();
        queueScheduler = new QueuedTaskScheduler(targetScheduler: TaskScheduler.Default, maxConcurrencyLevel: 1);
        ts_priority1 = queueScheduler.ActivateNewQueue(1);
    }
        private void button3_Click(object sender, EventArgs e)
    {
        QueueValue(pos, ts_priority1);
        pos++;
    }

    private void button4_Click(object sender, EventArgs e)
    {
        changeString(pos);
        pos++;
    }
    private void changeString (int position)
    {
        var bea = "This is Thread " + position + " starting";
        MethodInvoker Labelupdate = delegate
        {
            label2.Text = bea;
        };
        Invoke(Labelupdate);

        Thread.Sleep(3000);
        bea = "Thread " + position + " is ending";

        MethodInvoker Labelupdate1 = delegate
        {
            label2.Text = bea;
        };
        Invoke(Labelupdate1);
        Thread.Sleep(1000);
    }
    private void updateLabel (string Lab)
    {
        MethodInvoker Labelupdate = delegate
        {
            label2.Text = Lab;
        };
        Invoke(Labelupdate);
    }
    private Task QueueTask(Func<Task> f, TaskScheduler ts)
    {
        return Task.Factory.StartNew(f, CancellationToken.None, TaskCreationOptions.HideScheduler | TaskCreationOptions.DenyChildAttach, ts);
    }

    private Task QueueValue(int position, TaskScheduler ts)
    {
        return QueueTask(async () =>
        {
            label2.Text = "This is Thread " + position + " starting";
            Thread.Sleep(3000);
            label2.Text = "Thread " + position + " is ending";
            Thread.Sleep(1000);
        }, ts);
    }
QueuedTaskScheduler-queueScheduler;
专用任务调度器ts_优先级1;
int pos=0;
公共表格1()
{
初始化组件();
queueScheduler=新的QueuedTaskScheduler(targetScheduler:TaskScheduler.Default,maxConcurrencyLevel:1);
ts_priority1=queueScheduler.ActivateNewQueue(1);
}
私有无效按钮3\u单击(对象发送者,事件参数e)
{
队列值(位置、优先级1);
pos++;
}
私有无效按钮4_单击(对象发送者,事件参数e)
{
更改字符串(pos);
pos++;
}
私有无效更改字符串(int位置)
{
var bea=“这是线程”+位置+“开始”;
MethodInvoker Labelupdate=委托
{
label2.Text=bea;
};
调用(Labelupdate);
睡眠(3000);
bea=“线程”+位置+“正在结束”;
MethodInvoker Labelupdate1=委托
{
label2.Text=bea;
};
调用(Labelupdate1);
睡眠(1000);
}
私有void updateLabel(字符串实验室)
{
MethodInvoker Labelupdate=委托
{
label2.Text=Lab;
};
调用(Labelupdate);
}
专用任务队列任务(函数f,任务调度器ts)
{
返回Task.Factory.StartNew(f,CancellationToken.None,TaskCreationOptions.HidesScheduler | TaskCreationOptions.Denychildatach,ts);
}
专用任务队列值(int位置,TaskScheduler ts)
{
返回队列任务(异步()=>
{
label2.Text=“这是线程”+位置+“开始”;
睡眠(3000);
label2.Text=“线程”+位置+“正在结束”;
睡眠(1000);
},ts);
}

我解决了它。只需要一个信号灯。这和这个一样 代码如下:

private static SemaphoreSlim semaphore = new SemaphoreSlim(1);
 private Task QueueValue(int position, TaskScheduler ts)
    {
        return QueueTask(async () =>
        {
            await semaphore.WaitAsync();
            try
            {
                var at = "This is Thread " + position + " starting";
                updateLabel(at);
                await Task.Delay(3000);
                at = "Thread " + position + " is ending";
                updateLabel(at);
                await Task.Delay(1000);
            }
            finally
            {

                semaphore.Release();
            }

        }, ts);
    }

非常感谢

对于FIFO,请使用队列类。对于后进先出,使用堆栈类。当启动此代码时,我看不到标签在一个接一个地执行任务时发生变化。混合信号量和任务是一种气味。如果您想一次执行一个“任务”,可以使用ActionBlock。事实上,您可以使用TPL数据流创建具有不同并行度、负载平衡等的整个数据流管道library@PanagiotisKanavos在这里使用
信号灯
完全没有问题。它是专门为这种类型的用例设计的。TPL数据流如果可以,如果您想要更高级的功能,但如果您不需要它,那么这就可以了。@Servy[TPL Dataflow]中存在一个问题,其中信号量LIM实际上会导致阻塞。SemaphoreSlim不是一个本地构造,它在幕后使用了一些技巧。对于简单/高级的ActionBlock,您只需要
var block=newActionBlock(msg=>Process(msg))
然后您就可以开始排队工作了。@PanagiotisKanavos那么您是在声称两者一起使用存在问题,而不是单独使用其中一个来解决问题。差别很大。你建议在程序中安装一个完整的第三方工具只是为了添加一行代码,而不是使用一个简单的工具。对于这样的情况,没有理由这么做。@Servy,不,我是说人们应该更喜欢使用内置功能而不是重新发明轮子,特别是当问题是从另一种语言迁移时。NET提供了比Python的
async
更多的异步编程技术。需要用Python手工编码的东西可能已经在.NET中提供了