如何触发异步任务,但在返回 ActionResult 之前等待所有回调?

发布于 2024-11-10 11:37:20 字数 687 浏览 0 评论 0原文

我有一个 ASP.NET MVC 3 操作方法,它接受 HTTP POST 中的 HttpFileCollectionBase 。

在这种方法中,我需要调整图像大小并上传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 来触发异步任务,但那时我并不关心等待结果。

有什么想法吗?

I have an ASP.NET MVC 3 action method which accepts a HttpFileCollectionBase in the HTTP POST.

In this method, i need to resize and upload the image 3 times.

The action method currently looks like this:

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

Basically this is a user profile page, where they change their profile pic. The upload happens via jQuery AJAX.

Now, how can i fire off the three ResizeAndUpload calls as asynchronous tasks, but not return the action result until all three tasks have completed?

Previously i've been using Task.Factory.StartNew to fire off asynchronous tasks, but that was when i didn't care about waiting for the result.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

剧终人散尽 2024-11-17 11:37:20

一种简单的方法是使用 Join:

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 方法可能会在某个地方阻塞(在没有看到代码的情况下无法确定),在这种情况下,可能值得重构这些方法以使它们异步。

One simple way of doing it, is using Join:

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

It's possible though that the ResizeAndUpload method may be blocking somewhere (can't tell for sure without seeing the code) in which case it may be worthwhile to refactor those as well to make them async.

薆情海 2024-11-17 11:37:20

还使用 Task.Factory.StartNew 让它工作,类似于 @BFree 的答案:

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 是否更好。

Also got it working using Task.Factory.StartNew, similar to @BFree's answer:

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

Now sure if Thread or Task is better.

随遇而安 2024-11-17 11:37:20

使用 Task 和 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();
    }

希望这会有所帮助。

Different implementation that uses Task and 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();
    }

hope this helps.

墨小墨 2024-11-17 11:37:20

这是我的看法,使用方便的“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;
}

Here is my take on it, use a handy "Task.WaitAll" static method for waits..

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;
}
花桑 2024-11-17 11:37:20

MVC 操作还有一个异步模式,请参阅此链接:

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

您仍然可以使用任务,但不需要任何特殊处理来允许操作异步执行

There is also an async pattern for MVC actions, see this link:

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

you can still use Tasks, but don't need any special handling to allow the actions to execute async

柏拉图鍀咏恒 2024-11-17 11:37:20

您可以用子任务来组成一个任务。当所有子任务完成后,父任务将完成。

例子:

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

You could make up a task, with child tasks. The parent task will complete, when all child tasks have completed.

Example:

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");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文