【问题标题】:What Should I be using here? Threading? Async?我应该在这里使用什么?穿线?异步?
【发布时间】:2013-05-20 13:56:21
【问题描述】:

我不确定在这种情况下使用什么。

我有一个基本上可以做到这一点的 asp.net web api 方法

  1. 从用户附近的foursquare查找兴趣点。
  2. 使用四方位置在我的数据库中进行查询,以查找有关用户附近兴趣点的唯一数据。

但是,由于我需要存储一些四方信息以将我的唯一数据链接到该位置,因此我决定将所有信息存储在我的数据库中,并让我的数据库充当我的缓存系统。

这意味着我必须将任何新的兴趣点插入到我的数据库中,检查它是否存在,如果存在则跳过它,或者如果它存在检查最后一次刷新日期(foursquare 政策规定所有数据必须在之后刷新30 天),如果超过刷新日期,我必须更新数据。

我想减慢用户的速度,并且必须等待上述情况发生。我希望我的代码执行第 1 步,然后在执行第 2 步的同时执行我刚才提到的操作。

第 2 步完成后,我想返回数据并让用户继续使用。如果我的缓存系统没有完成,那么它应该继续运行,但不会让用户陷入困境。

我不会在第 2 步中使用这些新结果中的任何一个,就好像我正在插入它一样,那么此时我在该位置将没有任何数据。

不确定我是否需要创建一个线程或使用 async/await 来实现这一点。

编辑

这就是我想要做的事情

public HttpResponseMessage Get()
{
    // this will do a foursquare lookup to find all stores near the user
    // I want to insert them into my database and link it to my unquie data. 
    // stores pulled from foursquare will
    // a) Be new and not in my database
    // b) exist in my database but have been refreshed lately
    // c) have not been refreshed in timeframe of foursquare policy
    // THIS SHOULD WORK IN THE BACKGROUND
    storeService.PointsOfInterestNearUser(80, -130); //As you can see it is 
                        //void. Not sure where to put the async/await stuff

    // find this product. Should be happening at the same time as above line.
    var product = productService.FindProduct("Noodles");

    //This will get returned to the user. 
    // the new stores taht are being added in StoreNearUser 
    //won't effect this search as I will have not data on this new store
    // if existing store is being refreshed it is possible old 
    //address might be picked up...
    //I can live with that as I doubt the address will change much.

    // this should happen after product
    var allStores = storeService.FindStoresThatHaveItem(product);

    // this should be returned as soon as above line is finished. 
    //If StoreNearUser is not done, it should keep going but not hold up user.
    return allStores;
}
public void StoresNearUser(double latitude, double longitude)
{
    // get all categories I can about in foursquare. 
    //First time from db otherwise cached.
    List<StoreCategory> storeCategories = GetStoreCategories();

    // do a request and get everything in near the user
    //(provided it is also in a category I care about)
    var request = CreateFoursquareStoreRequest
                       (latitude, longitude, storeCategories);

    // do the actual call.
    var response = client.Execute<VenueSearch>(request);


    if (response.StatusCode == System.Net.HttpStatusCode.OK)
    {
// start going through the results, add or update or skip of entry will happen
        AddUpdateStores(storeCategories, response);
    }
    else
    {
        ErrorSignal.FromCurrentContext().Raise(response.ErrorException);
    }
}

编辑 2

public async Task StoresNearUser(double latitude, double longitude)
{
// get all categories I can about in foursquare. First time from db otherwise cached.
    List<StoreCategory> storeCategories = GetStoreCategories();

// do a request and get everything in near the user(provided it is also in a category I care about)
    var request = CreateFoursquareStoreRequest(latitude, longitude, storeCategories);

    await client.ExecuteAsync<VenueSearch>
              (  request
                 , response =>
                     {
                         if (response.StatusCode == System.Net.HttpStatusCode.OK)
                         {
                             AddUpdateStores(storeCategories, response);
                         }
                         else
                         {
                             ErrorSignal.FromCurrentContext()
                                        .Raise(response.ErrorException);
                         }
                     }
              );
}

给我这个错误

Cannot await 'RestSharp.RestRequestAsyncHandle'

我也不明白Taskvoid 之间的区别。从我读到的内容来看,如果您只使用Task,这意味着您没有发送任何意义,那么为什么不直接使用void

编辑 2 我找到了this post,向我展示了如何为 Restsharp 制作包装器。这不是我想要的 100%,但这是一个单独的问题。

public async Task StoresNearUser(double latitude, double longitude)
{
    List<StoreCategory> storeCategories = GetStoreCategories();

    var request = CreateFoursquareStoreRequest
                    (latitude, longitude, maxRadius, returnLimit, storeCategories);

    var response =  await client.GetResponseAsync(request);

    if (response.StatusCode == HttpStatusCode.OK)
    {
// had to use json.net right now as the wrapper does not expose restsharps deserilizer
        var venue = JsonConvert
                    .DeserializeObject<VenueSearch>(response.Content);
        AddUpdateStores(storeCategories, venue);
    }
    else
    {
        ErrorSignal.FromCurrentContext()
                   .Raise(response.ErrorException);
    }
}

public async Task<HttpResponseMessage>Get()
{
    await storeService.PointsOfInterestNearUser(80, -130);
    var product = productService.FindProduct("Noodles");
    var allStores = storeService.FindStoresThatHaveItem(product);
    return allStores;
 }

当我从调试器中观察时,它看起来一切正常。我认为productallStores 需要,因为我需要产品才能找到商店,但PointsOfInterestNearUser 应该与FindProduct 同时出现。

编辑 3 这是我的 FindProduct 方法。不知道要让我做什么异步,看起来一切都需要等待。

public ResponseResult<Product> FindProduct(string barcode)
    {
        ResponseResult<Product> responseResult = new ResponseResult<Product>();
        Product product = null;

        try
        {

            var findBarCode = context.Barcodes.Where(x => x.Code == barcode).Select(x => x.Product).FirstOrDefault();

            responseResult.Response = product;

            if (product == null)
            {
                responseResult.Status.Code = HttpStatusCode.NotFound;
            }
            else
            {
                responseResult.Status.Code = HttpStatusCode.OK;
            }
        }
        catch (SqlException ex)
        {
            ErrorSignal.FromCurrentContext().Raise(ex);
            responseResult.Status.Code = HttpStatusCode.InternalServerError;
            responseResult.Status.Message = GenericErrors.InternalError;
        }

        return responseResult;
    }

编辑 4

仍然不确定如何执行 Task.WhenAll()

 public async Task<HttpResponseMessage>Get()
    {
      Task[] tasks = new Task[2];
      tasks[0] = storeService.PointsOfInterestNearUser(80, -130);
      tasks[1] = productService.FindProduct("Noodles");

       await Task.WhenAll(tasks);

       // not sure how to get product back out. I looked in the debugger and saw a "Result" that has it but when I do tasks[1].Result inetllisene cannot find .Result
       var allStores = storeService.FindStoresThatHaveItem(product);
       return allStores;
     }

【问题讨论】:

  • 听起来像线程最好。如果您不关心更新数据库调用返回的信息,那么为什么要使用 async/await?你能开枪就忘记吗?
  • @KirkWoll:一点也不。 asyncawait 并不意味着多线程。
  • @Stephen,这是真的,我忘了这一切都可能发生在同一个线程上。哎呀。

标签: c# .net multithreading asynchronous async-await


【解决方案1】:

我建议为此使用async/await。更新缓存是可以接受从 ASP.NET 请求提前返回的罕见情况之一。您可以查看我的blog post on the subject 以获得一些有用的代码。

所以,像这样(简化为每个位置只查找一个“有趣的地方”):

public async Task<PlaceWithData> FindPlaceAsync(Location myLocation)
{
  Place place = await GetPlaceFromFoursquareAsync(myLocation);
  PlaceWithData ret = await GetExtraDataFromDatabaseAsync(place);
  if (ret.NeedsRefresh)
    BackgroundTaskManager.Run(() => UpdateDatabaseAsync(place, ret));
  return ret;
}

您可能还想考虑扩展 ASP.NET 缓存系统,而不是“滚动自己的”缓存。

【讨论】:

  • 我想我必须提供一个代码示例,这可能会显示我正在做的更多事情,因为我确实认为异步是一个很好的方法,但我遇到的问题是它基本上是无效的方法它不喜欢那样。
  • 我查看了您的代码示例。我建议您首先将其全部设置为async,然后再将其更改为提前返回。转换为async 时,我喜欢从内到外工作,所以我首先要看的是client.Execute(即,添加client.ExecuteAsync),然后在调用堆栈中向上工作。
  • 好的,我将客户端请求更改为 ExecuteAsync,但我不确定您的意思是“使其全部异步”。我也在使用 EF 5,当我只是进行客户端更改时,我现在收到此错误“操作无法完成,因为 DbContext 已被释放。”通常它会被 ninject 处理掉。
  • 你需要await调用ExecuteAsync,这意味着StoresNearUser应该从void变为async Task,这意味着Get需要调用await StoresNearUser,这意味着 Get 应该从 HttpResponseMessage 更改为 async Task&lt;HttpResponseMessage&gt;。接下来(假设这些正在访问数据库后端),将您的产品/商店服务更改为 async
  • 我不熟悉 RestSharp,但看起来 ExecuteAsync 不是 TAP method (follow this link to see what that means and how to adapt other asynchronous systems to support TAP)。关于async void vs async Task,请阅读my MSDN article
猜你喜欢
  • 2011-01-19
  • 2016-05-05
  • 1970-01-01
  • 2019-03-10
  • 2022-06-11
  • 2020-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多