我应该在这里使用什么?线程?异步?

时间:2013-05-17 22:23:26

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

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

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

  1. 从用户附近的foursquare查找兴趣点。
  2. 使用foursquare位置在我的数据库中进行查询,以查找有关用户附近兴趣点的唯一数据。
  3. 但是,由于我需要存储一些foursquare信息以链接到该位置的唯一数据,因此我决定将所有信息存储在我的数据库中,并让我的数据库充当我的缓存系统。

    这意味着我必须插入到我的数据库中的任何新的兴趣点,检查它是否存在,如果是,则跳过它或如果它存在检查最后刷新日期(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;
         }
    

1 个答案:

答案 0 :(得分:4)

我建议您使用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缓存系统,而不是“自己动手”缓存。