1

我正在编写一个 WCF 服务,它必须实现多线程才能调用另一个 3rd 方服务。

我正在使用 LINQ 创建一个“列表”并将对象列表发送给客户端。

“MyObject”有 5 个属性:

  • 3 静态存储在表中
  • 2 由第 3 方服务动态计算。

我需要生成线程来读取 2 个动态属性,超时时间为 30 秒。例子:

如果列表中有 6 个对象,

  • 我应该生成 6 个并行异步执行的线程,它们为它们的 2 个属性中的每一个调用 3rd 方服务。
  • 如果我在 30 秒内得到所有结果,我会将这 6 个具有所有属性的对象发送给客户端。
  • 如果我在 30 秒内没有收到任何对象的属性,我必须将该对象的属性设置为 NULL 并将对象列表返回给客户端。

我的代码如下所示:

List<Dials> lstDial = new List<Dials>();
foreach(var c in dialsToShow)
{
    int threadId;
    AsyncMethodCaller caller =
        new AsyncMethodCaller(MyMethodThatCalls3rdPartyService);

    IAsyncResult result = caller.BeginInvoke(userName, out threadId, null, null);

    while (!result.AsyncWaitHandle.WaitOne(30000, false))
         avgBI = caller.EndInvoke(out threadId, result);

    property4 = avgBI[0];
    property5= avgBI[1]; 

    var dashboardObj = _repository.FindQueryable<DashboardDial_Tbl>()
                   .Select(p => new DialDetails()
                   {
                       Id = p.DialId,
                       Name= p.DialName,
                       Type = p.DialType,
                       IndividualStat = property4,
                       GroupStat = proprty5         
                    }).SingleOrDefault();
      dials.Add(dashboardObj); 
}
reponse.dialsList = dials;

调用 3rd 方服务的方法有一个委托。它看起来像这样:

public delegate List<string> AsyncMethodCaller(
    string methodName, out int threadId);

private List<string> MyMethodThatCalls3rdPartyService(
    string userName, out int threadId)
{
    //Call the service
}

有人可以帮助我以另一种方式使用多线程来实现这一目标吗?我正在使用 .Net 4.0 和 VS2012。

4

1 回答 1

1

您可以使用Parallel并行运行并发任务:

public void DoStuff()
{
    var input = new[] {2, 3, 4};

    var results = new ConcurrentBag<string>();

    Parallel.ForEach(input, value =>
        {
            value += 10;
            results.Add(value.ToString());
        });

    foreach (var result in results)
    {
        Console.WriteLine(result);
    }
}

要进行超时,您必须在匿名方法中执行某些操作或使用CancellationToken.

或者您可以使用Task对象本身:

public void DoStuff()
{
    int input = 2;

    Task<string> task = Task<string>.Factory.StartNew(() =>
        {
            var output = (input + 10).ToString();
            return output;
        });

    //use this if you want to wait for all your tasks to complete
    Task.WaitAll(task);

    //Calling result will implicitly cause a wait if the task is not complete
    Console.WriteLine(task.Result);
}

要使任务超时,您可以单独调用Wait所有任务的超时,或者指定超时,WaitAll或者您可以再次使用 CancellationToken。

Task.WaitAll(new[] {task}, TimeSpan.FromSeconds(10));

编辑

我试图为您的示例提供一个实现,尽管有些地方需要澄清,并且示例的某些部分没有关联,所以我不得不做出一些假设:

  1. 拨号 = 拨号详情
  2. lstDial = 拨号
  3. “如果我在 30 秒内没有收到任何对象的属性,我必须将该对象的属性设置为 NULL”意味着您仍然想要其余的项目,而不是那个。

我已经使用并行 foreach 和任务的混合来完成它。

var dials = new List<DialDetails>();
Parallel.ForEach(dialsToShow, c =>
    {
        var task = Task<IList<string>>.Factory.StartNew(
            () => MyMethodThatCalls3rdPartyService(userName));
        // Get the item from the database while calling the service
        // However there appears to be no search going on here
        // the same type will always come back right?
        var dashboardObj = _repository.FindQueryable<DashboardDial_Tbl>()
                    .Select(p => new DialDetails()
                    {
                        Id = p.DialId,
                        Name= p.DialName,
                        Type = p.DialType      
                    }).SingleOrDefault();

        //Wait until the timeout
        task.Wait(TimeSpan.FromSeconds(30));

        //If it did not timeout or no other error occurred us the results
        if (dashboardObj != null && task.Status == TaskStatus.RanToCompletion)
        {
            //Need to do some checking here for indexes
            dashboardObj.IndividualStat = task.Result[0];
            dashboardObj.GroupStat = task.Result[1];
            dials.Add(dashboardObj);
        }
    });
reponse.dialsList = dials;

private IList<string> MyMethodThatCalls3rdPartyService(string userName)
{
    //Call the service
}
于 2013-09-19T15:21:32.487 回答