gpt4 book ai didi

c# - 一个单独的线程是否需要它自己的 VersionControlServer 实例才能与另一个线程同时工作?

转载 作者:太空宇宙 更新时间:2023-11-03 13:48:19 25 4
gpt4 key购买 nike

假设我的 C# 程序中有任意数量的线程。每个线程都需要通过查找历史来查找特定路径的变更集 ID。该方法如下所示:

public List<int> GetIdsFromHistory(string path, VersionControlServer tfsClient)
{
IEnumerable submissions = tfsClient.QueryHistory(
path,
VersionSpec.Latest,
0,
RecursionType.None, // Assume that the path is to a file, not a directory
null,
null,
null,
Int32.MaxValue,
false,
false);

List<int> ids = new List<int>();
foreach(Changeset cs in submissions)
{
ids.Add(cs.ChangesetId);
}
return ids;
}

我的问题是,每个线程都需要它自己的 VersionControlServer 实例还是一个就足够了?我的直觉告诉我,每个线程都需要自己的实例,因为 TFS SDK 使用 Web 服务,如果我真的要获得并行行为,我可能应该打开多个连接。如果我只使用一个连接,我的直觉告诉我,即使我有多个线程,我也会得到串行行为。

如果我需要与线程一样多的实例,我会考虑使用对象池模式,但是如果长时间不使用,连接会超时并关闭吗?在这方面,文档似乎很少。

最佳答案

使用 SAME 客户端的线程似乎是最快的选择。

这是一个测试程序的输出,该程序运行 4 次测试,每次测试 5 次,并以毫秒为单位返回平均结果。显然跨多个线程使用同一个客户端是最快的执行:

Parallel Pre-Alloc: Execution Time Average (ms): 1921.26044
Parallel AllocOnDemand: Execution Time Average (ms): 1391.665
Parallel-SameClient: Execution Time Average (ms): 400.5484
Serial: Execution Time Average (ms): 1472.76138

作为引用,这里是测试程序本身(也在 GitHub 上):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.Collections;
using System.Threading.Tasks;
using System.Diagnostics;

namespace QueryHistoryPerformanceTesting
{
class Program
{
static string TFS_COLLECTION = /* TFS COLLECTION URL */
static VersionControlServer GetTfsClient()
{
var projectCollectionUri = new Uri(TFS_COLLECTION);
var projectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(projectCollectionUri, new UICredentialsProvider());
projectCollection.EnsureAuthenticated();
return projectCollection.GetService<VersionControlServer>();
}

struct ThrArg
{
public VersionControlServer tfc { get; set; }
public string path { get; set; }
}

static List<string> PATHS = new List<string> {
// ASSUME 21 FILE PATHS
};

static int NUM_RUNS = 5;
static void Main(string[] args)
{
var results = new List<TimeSpan>();

for (int i = NUM_RUNS; i > 0; i--)
{
results.Add(RunTestParallelPreAlloc());
}
Console.WriteLine("Parallel Pre-Alloc: Execution Time Average (ms): " + results.Select(t => t.TotalMilliseconds).Average());

results.Clear();
for (int i = NUM_RUNS; i > 0; i--)
{
results.Add(RunTestParallelAllocOnDemand());
}
Console.WriteLine("Parallel AllocOnDemand: Execution Time Average (ms): " + results.Select(t => t.TotalMilliseconds).Average());

results.Clear();
for (int i = NUM_RUNS; i > 0; i--)
{
results.Add(RunTestParallelSameClient());
}
Console.WriteLine("Parallel-SameClient: Execution Time Average (ms): " + results.Select(t => t.TotalMilliseconds).Average());

results.Clear();
for (int i = NUM_RUNS; i > 0; i--)
{
results.Add(RunTestSerial());
}
Console.WriteLine("Serial: Execution Time Average (ms): " + results.Select(t => t.TotalMilliseconds).Average());
}

static TimeSpan RunTestParallelPreAlloc()
{
var paths = new List<ThrArg>();
paths.AddRange( PATHS.Select( x => new ThrArg { path = x, tfc = GetTfsClient() } ) );
return RunTestParallel(paths);
}

static TimeSpan RunTestParallelAllocOnDemand()
{
var paths = new List<ThrArg>();
paths.AddRange(PATHS.Select(x => new ThrArg { path = x, tfc = null }));
return RunTestParallel(paths);
}

static TimeSpan RunTestParallelSameClient()
{
var paths = new List<ThrArg>();
var _tfc = GetTfsClient();
paths.AddRange(PATHS.Select(x => new ThrArg { path = x, tfc = _tfc }));
return RunTestParallel(paths);
}

static TimeSpan RunTestParallel(List<ThrArg> args)
{
var allIds = new List<int>();

var stopWatch = new Stopwatch();
stopWatch.Start();
Parallel.ForEach(args, s =>
{
allIds.AddRange(GetIdsFromHistory(s.path, s.tfc));
}
);
stopWatch.Stop();

return stopWatch.Elapsed;
}

static TimeSpan RunTestSerial()
{
var allIds = new List<int>();
VersionControlServer tfsc = GetTfsClient();

var stopWatch = new Stopwatch();
stopWatch.Start();
foreach (string s in PATHS)
{
allIds.AddRange(GetIdsFromHistory(s, tfsc));
}
stopWatch.Stop();

return stopWatch.Elapsed;
}

static List<int> GetIdsFromHistory(string path, VersionControlServer tfsClient)
{
if (tfsClient == null)
{
tfsClient = GetTfsClient();
}

IEnumerable submissions = tfsClient.QueryHistory(
path,
VersionSpec.Latest,
0,
RecursionType.None, // Assume that the path is to a file, not a directory
null,
null,
null,
Int32.MaxValue,
false,
false);

List<int> ids = new List<int>();
foreach(Changeset cs in submissions)
{
ids.Add(cs.ChangesetId);
}
return ids;
}

关于c# - 一个单独的线程是否需要它自己的 VersionControlServer 实例才能与另一个线程同时工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14504621/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com