2

アプリケーションのパフォーマンスに関するいくつかのメトリックを構築するために、データベース + 他の関数への関数呼び出しのタイミングを計ることに興味があります。ストップウォッチとメトリクス オブジェクトを使用しましたが、一貫して正しい値が得られないようです。関数を呼び出すための経過時間がすべての呼び出しでまったく同じである場合があり、これは非現実的です...

問題の原因は Metrics オブジェクトのプロパティ値にあることがわかりました。1 つの Metrics オブジェクトの値は、他のスレッドによって生成された Metrics の他のインスタンスに値が割り当てられると上書きされます。各スレッドによって新しいインスタンスが作成されますが、プロパティ値は参照ごとのようです。

複数のスレッドで共有されるオブジェクトで一意性を達成するための最良のアプローチは何ですか?

以下のコード:

private Metrics Metrics;
private Stopwatch Stopwatch;
private int DegreeOfParallelism { get { return Convert.ToInt32(ConfigurationManager.AppSettings["DegreeOfParallelism"].ToString()); } }

var lOptions = new ParallelOptions() { MaxDegreeOfParallelism = DegreeOfParallelism };
Parallel.ForEach(RequestBag, lOptions, (lItem, loopState) =>
{
    if (!string.IsNullOrEmpty(lItem.XmlRequest))
    {
        try
        {
            Metrics = new Metrics();
            Stopwatch = new Stopwatch();
            Stopwatch.Start();
            ObjRef = new Object();
            lItem.XmlRequest = ObjRef.GetDecision(Username, Password);
            Stopwatch.Stop();
            Metrics.ElapsedTime = string.Format("{0:0.00}", Stopwatch.Elapsed.TotalSeconds);

            Stopwatch.Restart();
            if (!string.IsNullOrEmpty(DBConnectionString))
            {
                DataAccess = new DataAccess2(DBConnectionString);
                DataAccess.WriteToDB(lItem.XmlRequest);  
            }
            Stopwatch.Stop();
            Metrics.DbFuncCallTime = string.Format("{0:0.00}", Stopwatch.Elapsed.TotalSeconds); 
        }
        catch (Exception pEx)
        { 
            KeepLog(pEx);
            Metrics.HasFailed = true;
        }
        finally
        {
            ProcessedIdsBag.Add(lItem.OrderId);
            Metrics.ProcessedOrderId = lItem.OrderId;
            Metrics.DegreeOfParallelism = DegreeOfParallelism;
            Metrics.TotalNumOfOrders = NumberOfOrders;
            Metrics.TotalNumOfOrdersProcessed = ProcessedIdsBag.Count;
            pBackgroundWorker.ReportProgress(Metrics.GetProgressPercentage(NumberOfOrders, ProcessedIdsBag.Count), Metrics);

            RequestBag.TryTake(out lItem);
        }
    }
});

どんな助けでも大歓迎です。ありがとう、R

4

2 に答える 2

1

やりたいと思われるのは、反復ごとにメトリックオブジェクトを作成し、最後にそれらを集約することです。

private ConcurrentBag<Metrics> allMetrics = new ConcurrentBag<Metrics>();
private int DegreeOfParallelism { get { return Convert.ToInt32(ConfigurationManager.AppSettings["DegreeOfParallelism"].ToString()); } }

var lOptions = new ParallelOptions() { MaxDegreeOfParallelism = DegreeOfParallelism };
Parallel.ForEach(RequestBag, lOptions, (lItem, loopState) =>
{
    if (!string.IsNullOrEmpty(lItem.XmlRequest))
    {
        try
        {
            var Metrics = new Metrics();
            var Stopwatch = new Stopwatch();
            Stopwatch.Start();
            ObjRef = new Object();
            lItem.XmlRequest = ObjRef.GetDecision(Username, Password);
            Stopwatch.Stop();
            Metrics.ElapsedTime = string.Format("{0:0.00}", Stopwatch.Elapsed.TotalSeconds);

            Stopwatch.Restart();
            if (!string.IsNullOrEmpty(DBConnectionString))
            {
                DataAccess = new DataAccess2(DBConnectionString);
                DataAccess.WriteToDB(lItem.XmlRequest);  
            }
            Stopwatch.Stop();
            Metrics.DbFuncCallTime = string.Format("{0:0.00}", Stopwatch.Elapsed.TotalSeconds); 
        }
        catch (Exception pEx)
        { 
            KeepLog(pEx);
            Metrics.HasFailed = true;
        }
        finally
        {
            ProcessedIdsBag.Add(lItem.OrderId);
            Metrics.ProcessedOrderId = lItem.OrderId;
            Metrics.DegreeOfParallelism = DegreeOfParallelism;
            Metrics.TotalNumOfOrders = NumberOfOrders;
            Metrics.TotalNumOfOrdersProcessed = ProcessedIdsBag.Count;
            pBackgroundWorker.ReportProgress(Metrics.GetProgressPercentage(NumberOfOrders, ProcessedIdsBag.Count), Metrics);

            RequestBag.TryTake(out lItem);
            allMetrics.add(Metrics);
        }
    }
});

// Aggregate everything in AllMetrics here
于 2012-01-27T15:52:03.687 に答える
1

Stopwatch および Metrics 変数のスコープを変更する必要があります。

現在、各スレッドは同じ Metrics 変数を共有しています。スレッドが try ブロックに入るとすぐに、Metrics の新しいインスタンスを (正しく) 作成しますが、それを共有変数に入れます (正しくない)。他のすべてのスレッドは、次のスレッドが来てプロセス全体を最初からやり直すまで、共有変数を読み取るときにその新しいインスタンスを認識します。

動く

private Metrics Metrics;
private Stopwatch Stopwatch;

ループのすぐ内側に

Parallel.ForEach(RequestBag, lOptions, (lItem, loopState) =>
{
    private Metrics Metrics;
    private Stopwatch Stopwatch;
...

これにより、ループを介した各反復に、オブジェクトの独自のインスタンスを格納するための独自の変数が与えられます。

于 2012-01-30T18:25:06.157 に答える