कृपया पृष्ठभूमि जानकारी के लिए इस सवाल का देखें:CorrelationManager.LogicalOperationStack Parallel.For, कार्य, धागे, आदि के साथ संगत है
How do Tasks in the Task Parallel Library affect ActivityID?
यही प्रश्न पूछता कैसे कार्य Trace.CorrelationManager.ActivityId प्रभावित करते हैं। @ ग्रेग सैमसन ने एक परीक्षण कार्यक्रम के साथ अपने स्वयं के प्रश्न का उत्तर दिया कि गतिविधि आईडी कार्य के संदर्भ में विश्वसनीय है। परीक्षण कार्यक्रम टास्क प्रतिनिधि की शुरुआत में एक गतिविधि आईडी सेट करता है, काम को अनुकरण करने के लिए सोता है, फिर यह सुनिश्चित करने के लिए गतिविधि आईडी को अंत में जांचता है कि यह वही मान है (यानी कि यह किसी अन्य थ्रेड द्वारा संशोधित नहीं किया गया है)। कार्यक्रम सफलतापूर्वक चलाता है।
सूत्रण, कार्य, और समानांतर आपरेशन (अंत में प्रवेश के लिए बेहतर संदर्भ प्रदान करने) के लिए अन्य "संदर्भ" विकल्प पर शोध करते हुए मैं Trace.CorrelationManager.LogicalOperationStack साथ एक अजीब मुद्दा में भाग (यह वैसे भी मेरे लिए अजीब था)। मैंने नीचे अपने प्रश्न के लिए अपना "उत्तर" कॉपी किया है।
मुझे लगता है कि यह पर्याप्त रूप से मुद्दा यह है कि मैं में भाग का वर्णन करता है (Trace.CorrelationManager.LogicalOperationStack जाहिरा तौर पर भ्रष्ट हो रही है - या कुछ और - जब Parallel.For के संदर्भ में प्रयोग किया जाता है, लेकिन केवल तभी Parallel.For अपने आप में संलग्न है एक तार्किक ऑपरेशन)।
यहाँ मेरी प्रश्न हैं:
Trace.CorrelationManager.LogicalOperationStack चाहिए Parallel.For साथ प्रयोग करने योग्य हो सकता है? यदि हां, तो क्या यह एक फर्क पड़ता है यदि एक तार्किक ऑपरेशन समानांतर के साथ पहले से ही प्रभावी है। शुरू हो गया है?
क्या समानांतर के साथ LogicalOperationStack का उपयोग करने का एक "सही" तरीका है? के लिए? क्या मैं इस नमूना कार्यक्रम को अलग-अलग कोड कर सकता हूं ताकि यह "काम करता है"? "काम करता है" से मेरा मतलब है कि लॉजिकलऑपरेशनस्टैक में हमेशा प्रविष्टियों की अपेक्षित संख्या होती है और प्रविष्टियां स्वयं अपेक्षित प्रविष्टियां होती हैं।
मैं धागे और ThreadPool धागे का उपयोग कर कुछ अतिरिक्त परीक्षण किया है, लेकिन मैं वापस जाने के लिए और उन लोगों के परीक्षण पुन: प्रयास करता है, तो मैं इसी तरह की समस्याओं में भाग देखने के लिए करना होगा।
मैं कहूंगा कि यह प्रतीत होता है कि कार्य/समानांतर धागे और थ्रेडपूल धागे ट्रेस "उत्तराधिकारी" को "उत्तराधिकारी" करते हैं। सक्रियता आईडी और ट्रेस। सहसंबंध प्रबंधक। लॉजिकलऑपरेशन पैरेंट थ्रेड से मूल्यों को रोकें। यह अपेक्षा की जाती है क्योंकि इन मानों को CallContext की लॉजिकलसेटडेट विधि (सेटडाटा के विपरीत) का उपयोग करके सहसंबंध प्रबंधक द्वारा संग्रहीत किया जाता है।
फिर, "जवाब" है कि मैं नीचे पोस्ट के लिए मूल संदर्भ प्राप्त करने के लिए इस सवाल का वापस संदर्भ लें:
How do Tasks in the Task Parallel Library affect ActivityID?
भी देखें इस समान प्रश्न (जो अब तक उत्तर नहीं दिया गया) माइक्रोसॉफ्ट के समानांतर एक्सटेंशन फ़ोरम पर:
[शुरू चिपकाएं]
कृपया इसे मेरे उत्तर को उत्तर के रूप में क्षमा करें क्योंकि यह वास्तव में आपके प्रश्न का उत्तर नहीं है, हालांकि, यह आपके प्रश्न से संबंधित है क्योंकि यह सहसंबंध प्रबंधक व्यवहार और धागे/कार्य/आदि से संबंधित है।मैं multithreading परिदृश्यों में अतिरिक्त संदर्भ प्रदान करने के लिए CorrelationManager के LogicalOperationStack
(और StartLogicalOperation/StopLogicalOperation
विधियों) का उपयोग कर देख रहा हूं।
मैंने आपका उदाहरण लिया और समानांतर में समानांतर में काम करने की क्षमता जोड़ने के लिए थोड़ा सा संशोधित किया। इसके लिए। इसके अलावा, मैं StartLogicalOperation/StopLogicalOperation
का उपयोग ब्रैकेट (आंतरिक रूप से) DoLongRunningWork
पर करता हूं।
DoLongRunningWork
StartLogicalOperation
Thread.Sleep(3000)
StopLogicalOperation
मैं ने पाया है कि अगर मैं अपने कोड में ये तार्किक संचालन जोड़ने (कम या ज्यादा होता है), तार्किक operatins के सभी सिंक में रहते हैं (: वैचारिक रूप से, DoLongRunningWork
इस हर बार निष्पादित किया जाता है की तरह कुछ करता है ढेर पर संचालन की हमेशा अपेक्षित संख्या और ढेर पर संचालन के मूल्य हमेशा अपेक्षित होते हैं)।
मेरे अपने कुछ परीक्षणों में मैंने पाया कि यह हमेशा मामला नहीं था। तार्किक ऑपरेशन स्टैक "दूषित" हो रहा था। सबसे अच्छा स्पष्टीकरण मैं साथ आ सकता हूं कि "बच्चे" धागे से निकलने पर कॉलकॉन्टेक्स्ट जानकारी की "विलय" वापस "मूल" थ्रेड संदर्भ में "पुरानी" बाल थ्रेड संदर्भ जानकारी (लॉजिकल ऑपरेशन) " विरासत "एक और भाई बच्चे धागे द्वारा।
समस्या भी "कार्यकर्ता धागे" में से एक (या जो भी वे में बुलाया जाना चाहिए के रूप में तथ्य यह है कि Parallel.For जाहिरा तौर पर मुख्य थ्रेड (लिखित रूप में कम से कम उदाहरण के कोड में) का उपयोग करता है से संबंधित हो सकती समांतर डोमेन)। जब भी DoLongRunningWork निष्पादित किया जाता है, तो एक नया लॉजिकल ऑपरेशन शुरू होता है (शुरुआत में) और बंद हो जाता है (अंत में) (यानी, लॉजिकलऑपरेशनस्टैक पर धक्का दिया जाता है और इसके पीछे से पॉप किया जाता है)। यदि मुख्य धागे में पहले से ही एक तार्किक ऑपरेशन है और यदि डॉन लोंगरिंग वर्क मुख्य थ्रेड पर निष्पादित करता है, तो एक नया लॉजिकल ऑपरेशन शुरू हो गया है, इसलिए मुख्य थ्रेड के लॉजिकलऑपरेशनस्टैक में अब दो ऑपरेशन हैं। DoLongRunningWork के किसी भी बाद के निष्पादन (जब तक DoLongRunningWork का यह "पुनरावृत्ति" मुख्य धागे पर निष्पादित हो रहा है) (जाहिर है) मुख्य थ्रेड के लॉजिकलऑपरेशनस्टैक (जो अब केवल एक अपेक्षित ऑपरेशन के बजाए दो ऑपरेशन है) का वारिस करेगा।
मुझे यह पता लगाने में काफी समय लगा कि लॉजिकलऑपरेशनस्टैक का व्यवहार आपके उदाहरण के मेरे संशोधित संस्करण की तुलना में मेरे उदाहरण में अलग क्यों था। आखिरकार मैंने देखा कि मेरे कोड में मैंने पूरे कार्यक्रम को लॉजिकल ऑपरेशन में ब्रैकेट किया था, जबकि आपके टेस्ट प्रोग्राम के मेरे संशोधित संस्करण में मैंने नहीं किया था। निहितार्थ यह है कि मेरे परीक्षण कार्यक्रम में, हर बार जब मेरा "काम" किया गया था (DoLongRunningWork के समान), पहले से ही एक तार्किक ऑपरेशन प्रभावी था। आपके परीक्षण कार्यक्रम के मेरे संशोधित संस्करण में, मैंने पूरे कार्यक्रम को लॉजिकल ऑपरेशन में ब्रैकेट नहीं किया था।
इसलिए, जब मैंने आपके परीक्षण कार्यक्रम को लॉजिकल ऑपरेशन में पूरे प्रोग्राम को ब्रैकेट करने के लिए संशोधित किया और यदि मैं समांतर का उपयोग कर रहा हूं। इसके लिए, मैं बिल्कुल वही समस्या में भाग गया।
ऊपर वैचारिक मॉडल का उपयोग करना, यह सफलतापूर्वक चलेंगे:
Parallel.For
DoLongRunningWork
StartLogicalOperation
Sleep(3000)
StopLogicalOperation
यह अंततः जाहिरा तौर पर सिंक LogicalOperationStack के बाहर एक के कारण जोर करते हैं:
StartLogicalOperation
Parallel.For
DoLongRunningWork
StartLogicalOperation
Sleep(3000)
StopLogicalOperation
StopLogicalOperation
यहाँ मेरी नमूना कार्यक्रम है। यह आपके जैसा ही है कि इसमें एक DoLongRunningWork विधि है जो ActivityId के साथ-साथ LogicalOperationStack में हेरफेर करती है। मेरे पास DoLongRunningWork की लात मारने के दो स्वाद भी हैं। एक स्वाद समान कार्यों का उपयोग करता है जो एक समानांतर का उपयोग करता है। के लिए। प्रत्येक स्वाद को भी निष्पादित किया जा सकता है कि संपूर्ण समांतर ऑपरेशन लॉजिकल ऑपरेशन में संलग्न है या नहीं। तो, समानांतर संचालन निष्पादित करने के कुल 4 तरीके हैं। प्रत्येक को आज़माने के लिए, वांछित "उपयोग करें ..." विधि को असम्बद्ध करें, पुनः संकलित करें और चलाएं।UseTasks
, UseTasks(true)
, और UseParallelFor
सभी को पूरा होने के लिए तैयार होना चाहिए। UseParallelFor(true)
कुछ बिंदु पर जोर देगी क्योंकि LogicalOperationStack में प्रविष्टियों की अपेक्षित संख्या नहीं है।
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace CorrelationManagerParallelTest
{
class Program
{
static void Main(string[] args)
{
//UseParallelFor(true) will assert because LogicalOperationStack will not have expected
//number of entries, all others will run to completion.
UseTasks(); //Equivalent to original test program with only the parallelized
//operation bracketed in logical operation.
////UseTasks(true); //Bracket entire UseTasks method in logical operation
////UseParallelFor(); //Equivalent to original test program, but use Parallel.For
//rather than Tasks. Bracket only the parallelized
//operation in logical operation.
////UseParallelFor(true); //Bracket entire UseParallelFor method in logical operation
}
private static List<int> threadIds = new List<int>();
private static object locker = new object();
private static int mainThreadId = Thread.CurrentThread.ManagedThreadId;
private static int mainThreadUsedInDelegate = 0;
// baseCount is the expected number of entries in the LogicalOperationStack
// at the time that DoLongRunningWork starts. If the entire operation is bracketed
// externally by Start/StopLogicalOperation, then baseCount will be 1. Otherwise,
// it will be 0.
private static void DoLongRunningWork(int baseCount)
{
lock (locker)
{
//Keep a record of the managed thread used.
if (!threadIds.Contains(Thread.CurrentThread.ManagedThreadId))
threadIds.Add(Thread.CurrentThread.ManagedThreadId);
if (Thread.CurrentThread.ManagedThreadId == mainThreadId)
{
mainThreadUsedInDelegate++;
}
}
Guid lo1 = Guid.NewGuid();
Trace.CorrelationManager.StartLogicalOperation(lo1);
Guid g1 = Guid.NewGuid();
Trace.CorrelationManager.ActivityId = g1;
Thread.Sleep(3000);
Guid g2 = Trace.CorrelationManager.ActivityId;
Debug.Assert(g1.Equals(g2));
//This assert, LogicalOperation.Count, will eventually fail if there is a logical operation
//in effect when the Parallel.For operation was started.
Debug.Assert(Trace.CorrelationManager.LogicalOperationStack.Count == baseCount + 1, string.Format("MainThread = {0}, Thread = {1}, Count = {2}, ExpectedCount = {3}", mainThreadId, Thread.CurrentThread.ManagedThreadId, Trace.CorrelationManager.LogicalOperationStack.Count, baseCount + 1));
Debug.Assert(Trace.CorrelationManager.LogicalOperationStack.Peek().Equals(lo1), string.Format("MainThread = {0}, Thread = {1}, Count = {2}, ExpectedCount = {3}", mainThreadId, Thread.CurrentThread.ManagedThreadId, Trace.CorrelationManager.LogicalOperationStack.Peek(), lo1));
Trace.CorrelationManager.StopLogicalOperation();
}
private static void UseTasks(bool encloseInLogicalOperation = false)
{
int totalThreads = 100;
TaskCreationOptions taskCreationOpt = TaskCreationOptions.None;
Task task = null;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
if (encloseInLogicalOperation)
{
Trace.CorrelationManager.StartLogicalOperation();
}
Task[] allTasks = new Task[totalThreads];
for (int i = 0; i < totalThreads; i++)
{
task = Task.Factory.StartNew(() =>
{
DoLongRunningWork(encloseInLogicalOperation ? 1 : 0);
}, taskCreationOpt);
allTasks[i] = task;
}
Task.WaitAll(allTasks);
if (encloseInLogicalOperation)
{
Trace.CorrelationManager.StopLogicalOperation();
}
stopwatch.Stop();
Console.WriteLine(String.Format("Completed {0} tasks in {1} milliseconds", totalThreads, stopwatch.ElapsedMilliseconds));
Console.WriteLine(String.Format("Used {0} threads", threadIds.Count));
Console.WriteLine(String.Format("Main thread used in delegate {0} times", mainThreadUsedInDelegate));
Console.ReadKey();
}
private static void UseParallelFor(bool encloseInLogicalOperation = false)
{
int totalThreads = 100;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
if (encloseInLogicalOperation)
{
Trace.CorrelationManager.StartLogicalOperation();
}
Parallel.For(0, totalThreads, i =>
{
DoLongRunningWork(encloseInLogicalOperation ? 1 : 0);
});
if (encloseInLogicalOperation)
{
Trace.CorrelationManager.StopLogicalOperation();
}
stopwatch.Stop();
Console.WriteLine(String.Format("Completed {0} tasks in {1} milliseconds", totalThreads, stopwatch.ElapsedMilliseconds));
Console.WriteLine(String.Format("Used {0} threads", threadIds.Count));
Console.WriteLine(String.Format("Main thread used in delegate {0} times", mainThreadUsedInDelegate));
Console.ReadKey();
}
}
}
की अगर LogicalOperationStack Parallel.For साथ इस्तेमाल किया जा सकता इस पूरे मुद्दे (और/या अन्य सूत्रण/टास्क निर्माण करती है) या कैसे यह शायद गुण अपने आप ही सवाल किया जा सकता है। शायद मैं एक प्रश्न पोस्ट करूंगा। इस बीच, मुझे आश्चर्य है कि क्या आपके पास इस पर कोई विचार है (या, मुझे आश्चर्य है कि आपने लॉजिकलऑपरेशनस्टैक का उपयोग करने पर विचार किया था क्योंकि गतिविधि आईडी सुरक्षित होने लगती है)।
[अंत चिपकाएं]
किसी को भी इस मुद्दे पर कोई विचार है?
लॉजिकलऑपरेशनस्टैक और समांतर पर किसी भी विचार या विचार। के लिए? – wageoghe
पूरी तरह से शोध के लिए धन्यवाद जो मुझे अपराधी को ढूंढने से बचाता है :) –