2011-06-01 13 views
3

我有一个ASP.NET MVC 3操作方法,它接受HTTP POST中的HttpFileCollectionBase如何激发异步任务,但在返回ActionResult之前等待所有回调?

在这种方法中,我需要调整大小和上传图像3次。

的操作方法目前看起来是这样的:

public ActionResult ChangeProfilePicture() 
{ 
    var fileUpload = Request.Files[0]; 

    ResizeAndUpload(fileUpload.InputStream, Size.Original); 
    ResizeAndUpload(fileUpload.InputStream, Size.Profile); 
    ResizeAndUpload(fileUpload.InputStream, Size.Thumb); 

    return Content("Success", "text/plain"); 
} 

基本上这是用户的个人资料页,在这里他们改变他们的个人资料照片。上传通过jQuery AJAX发生。

现在,我如何才能将三个ResizeAndUpload调用作为异步任务触发,但在所有三个任务完成之前不会返回操作结果?

以前我一直在使用Task.Factory.StartNew来触发异步任务,但那是当我不在乎等待结果。

任何想法?

回答

7

一个这样做的简单的方法,是用加入:

public ActionResult ChangeProfilePicture() 
{ 
    var fileUpload = Request.Files[0]; 
    var threads = new Thread[3]; 
    threads[0] = new Thread(()=>ResizeAndUpload(fileUpload.InputStream, Size.Original)); 
    threads[1] = new Thread(()=>ResizeAndUpload(fileUpload.InputStream, Size.Profile)); 
    threads[2] = new Thread(()=>ResizeAndUpload(fileUpload.InputStream, Size.Thumb)); 

    threads[0].Start(); 
    threads[1].Start(); 
    threads[2].Start(); 

    threads[0].Join(); 
    threads[1].Join(); 
    threads[2].Join(); 

    return Content("Success", "text/plain"); 
} 

这有可能,虽然该ResizeAndUpload方法可以某处阻塞(不能肯定地说没有看到代码)在这种情况下,它可能值得重构这些以使它们异步。

+0

调整大小和上传做两两件事:1)使用GDI,2)上载图像以亚马逊调整大小图像。 GDI的速度很快,这是亚马逊上传需要一段时间(对于2 MB文件,大约需要10秒)。所以这就是为什么我想要异步做它们。所以没有阻塞,只是S3服务器上传滞后。 – RPM1984 2011-06-01 00:28:45

+0

上传到Amazon的代码是异步的吗?如果不是,那么这三个线程就会坐在那里,在等待亚马逊响应时被阻塞。这并不好,特别是如果这个Action可以被多个请求同时调用。看看你是否可以将这些调用转换为异步调用。它可能会使事情变得复杂一点,但非常值得... – BFree 2011-06-01 00:32:26

+0

是的,亚马逊上传是同步的。但我想等待它,因为我想使用客户端脚本来刷新用户的个人资料照片。当然,另一种方法是在不关心回调的情况下进行上传异步操作,并且只会显示“您的上传已排队等待处理”等信息 – RPM1984 2011-06-01 00:35:27

6

也得到了它的工作用Task.Factory.StartNew,类似@贝丽的回答是:

public ActionResult ChangeProfilePicture() 
{ 
    var fileUpload = Request.Files[0]; 
    var threads = new Task[3]; 
    threads[0] = Task.Factory.StartNew(()=>ResizeAndUpload(fileUpload.InputStream, Size.Original)); 
    threads[1] = Task.Factory.StartNew(()=>ResizeAndUpload(fileUpload.InputStream, Size.Profile)); 
    threads[2] = Task.Factory.StartNew(()=>ResizeAndUpload(fileUpload.InputStream, Size.Thumb)); 

    Task.WaitAll(threads, 120000); // wait for 2mins. 

    return Content("Success", "text/plain"); 
} 

现在知道,如果ThreadTask更好。

+0

我认为@Bfree的使用Join()的答案可能更好,因为它不依赖于任意等待时间(例如2分钟) – Jedidja 2011-06-01 01:06:12

+3

@Jedidja - 这是我可以省略的可选参数。 – RPM1984 2011-06-01 01:31:47

0

还为MVC行动异步模式,看到此链接:

http://msdn.microsoft.com/en-us/library/ee728598.aspx

你仍然可以使用任务,而且不需要任何特殊处理,让行动来执行异步

+0

但事情是,我不希望'client-> myserver'调用是异步的,我希望'myserver-> amazon'调用是ascynhronous。 – RPM1984 2011-06-01 00:48:48

+0

gotcha。另一种选择是使用3个Task实例以及3个WaitHandles,如ManualResetEvent。我会用此代码示例发布另一个答案 – 2011-06-01 01:02:53

1

使用任务和ManualResetEvent的

public ActionResult Sample() 
    { 
     var wh1 = new ManualResetEvent(false); 
     var wh2 = new ManualResetEvent(false); 
     var wh3 = new ManualResetEvent(false); 

     Task.Factory.StartNew(new Action<object>(wh => 
     { 
      // DoSomething(); 
      var handle = (ManualResetEvent)wh; 
      handle.Set(); 
     }), wh1); 

     Task.Factory.StartNew(new Action<object>(wh => 
     { 
      // DoSomething(); 
      var handle = (ManualResetEvent)wh; 
      handle.Set(); 
     }), wh2); 

     Task.Factory.StartNew(new Action<object>(wh => 
     { 
      // DoSomething(); 
      var handle = (ManualResetEvent)wh; 
      handle.Set(); 
     }), wh3); 

     WaitHandle.WaitAll(new[] { wh1, wh2, wh3 }); 

     return View(); 
    } 

希望这可以帮助不同的实现。

+0

我可能会缺少一些东西,但是这与下面的答案基本上不一样,但使用更多的代码板代码? – RPM1984 2011-06-01 01:31:13

+0

是的,但不同之处在于,您可以控制何时从阻塞中释放任务 – 2011-06-01 02:15:11

1

这是我对了,一个方便的“Task.WaitAll”静态方法等待..

public MyViewModel LoadData() 
{ 
    MyViewModel viewModel = null; 

    try 
    { 
     Task.Factory.StartNew(() => 
      { 
       var task1 = Task<MyViewModel>.Factory.StartNew(() => 
       { 
        return BuildMyViewModel(args); 
       }); 

       var task2 = Task<ViewModel2>.Factory.StartNew(() => 
       { 
        return BuildViewModel2(args); 
       }); 

       var task3 = Task<ViewModel3>.Factory.StartNew(() => 
       { 
        return BuildViewModel3(args); 
       }); 

       Task.WaitAll(task1, task2, task3); 

       viewModel = task1.Result; 

       viewModel.ViewModel2 = task2.Result; 
       viewModel.ViewModel3 = task3.Result; 

      }).Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     System.Diagnostics.Trace.WriteLine(ex.StackTrace); 
     // ... 
    } 

    return viewModel; 
} 
0

你可以做一个任务,与子任务。所有子任务完成后,父任务将完成。

实施例:

public ActionResult ChangeProfilePicture() 
{ 
    var fileUpload = Request.Files[0]; 

    Task.Factory.StartNew(() => 
    { 
     Task.Factory.StartNew(() => 
      ResizeAndUpload(fileUpload.InputStream, Size.Original), 
      TaskCreationOptions.AttachedToParent); 

     Task.Factory.StartNew(() => 
      ResizeAndUpload(fileUpload.InputStream, Size.Profile), 
      TaskCreationOptions.AttachedToParent); 

     Task.Factory.StartNew(() => 
      ResizeAndUpload(fileUpload.InputStream, Size.Thumb), 
      TaskCreationOptions.AttachedToParent); 
    }).Wait(); 

    return Content("Success", "text/plain"); 
} 
相关问题