与限制并发执行并行执行

时间:2014-08-20 06:34:59

标签: c# multithreading silverlight asynchronous task-parallel-library

我想在Silverlight 5中并行执行异步操作,并且有限的可靠性。

我的代码就像:

    public async void btn_click(object s, RoutedEventArgs e)
    {
        await DoAllWork();
    }

    private async Task DoAllWork()
    {
        //Get work to do
        int[] wrk = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        //Start the tasks
        Task[] tasks = new Task[wrk.Length];
        for (int i = 0; i < wrk.Length; i++)
        {
            int item = wrk[i];
            tasks[i] = WorkSingleItem(item);
        }
        await TaskEx.WhenAll(tasks);
    }

    private async Task WorkSingleItem(int item)
    {
        //a very long operation
        var response = await Request(item);
        await Handle(response);
    }

我找到了这篇文章:http://msdn.microsoft.com/en-us/library/ee789351(v=vs.110).aspx

我如何等待我的工作方法,即使用“有限并发调度程序”启动所有长时间操作,并且每个项目都不依赖于同步上下文来避免在UI线程中执行代码...

2 个答案:

答案 0 :(得分:2)

由于您的长时间操作是异步处理I / O,并且有限并发的目的是避免DDoS,因此TaskScheduler是一个不正确的解决方案。这是因为TaskScheduler仅控制活动任务(运行或阻止);当任务通过await返回其调度程序时,它不再被视为&#34;活动&#34;。因此,如果您的I / O是异步的,则TaskScheduler无法用于阻止DDoS。

正确的解决方案是使用类似async-compatible semaphore

的内容
public async void btn_click(object s, RoutedEventArgs e)
{
  await Task.Run(() => DoAllWork());
}

private async Task DoAllWork()
{
  int[] wrk = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  var semaphore = new AsyncSemaphore(4);

  var tasks = wrk.Select(x => WorkSingleItem(x, semaphore));

  await TaskEx.WhenAll(tasks);
}

private async Task WorkSingleItem(int item, AsyncSemaphore semaphore)
{
  await semaphore.WaitAsync();
  try
  {
    var response = await Request(item);
    await Handle(response);
  }
  finally
  {
    semaphore.Release();
  }
}

答案 1 :(得分:0)

您可以创建一种只允许一次执行特定数量的给定任务的队列类型:

public class FixedParallelismQueue
{
    private SemaphoreSlim semaphore;
    public FixedParallelismQueue(int maxDegreesOfParallelism)
    {
        semaphore = new SemaphoreSlim(maxDegreesOfParallelism,
            maxDegreesOfParallelism);
    }

    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();
        }
    }
}

这会让你写:

private Task DoAllWork()
{
    int[] work = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    var queue = new FixedParallelismQueue(maxDegreesOfParallelism);
    var tasks = work.Select(n => queue.Enqueue(() => WorkSingleItem(n));
    return TaskEx.WhenAll(tasks);
}