मेरी इस पोस्टिंग को माफ करें:
Completed 100 tasks in 23097 milliseconds
Used 23 threads
TaskCreationOptions.LongRunning को taskCreationOpt बदलने अलग परिणाम दे दी है एक उत्तर के रूप में यह वास्तव में आपके प्रश्न का उत्तर नहीं देता है, हालांकि, यह आपके प्रश्न से संबंधित है क्योंकि यह सहसंबंध प्रबंधक व्यवहार और धागे/कार्य/आदि से संबंधित है। मैं multithreading परिदृश्यों में अतिरिक्त संदर्भ प्रदान करने के लिए CorrelationManager के LogicalOperationStack
(और StartLogicalOperation/StopLogicalOperation
विधियों) का उपयोग कर देख रहा हूं।
मैंने आपका उदाहरण लिया और समानांतर में समानांतर में काम करने की क्षमता जोड़ने के लिए थोड़ा सा संशोधित किया। इसके लिए। इसके अलावा, मैं StartLogicalOperation/StopLogicalOperation
का उपयोग ब्रैकेट (आंतरिक रूप से) DoLongRunningWork
पर करता हूं।
DoLongRunningWork
StartLogicalOperation
Thread.Sleep(3000)
StopLogicalOperation
मैं ने पाया है कि अगर मैं अपने कोड में ये तार्किक संचालन जोड़ने (कम या ज्यादा होता है), तार्किक operatins के सभी सिंक में रहते हैं (: वैचारिक रूप से, DoLongRunningWork
इस हर बार निष्पादित किया जाता है की तरह कुछ करता है ढेर पर संचालन की हमेशा अपेक्षित संख्या और ढेर पर संचालन के मूल्य हमेशा अपेक्षित होते हैं)।
मेरे अपने कुछ परीक्षणों में मैंने पाया कि यह हमेशा मामला नहीं था। तार्किक ऑपरेशन स्टैक "दूषित" हो रहा था। सबसे अच्छा स्पष्टीकरण मैं साथ आ सकता हूं कि "बच्चे" धागे से निकलने पर कॉलकॉन्टेक्स्ट जानकारी की "विलय" वापस "मूल" थ्रेड संदर्भ में "पुरानी" बाल थ्रेड संदर्भ जानकारी (लॉजिकल ऑपरेशन) " विरासत "एक और भाई बच्चे धागे द्वारा।
समस्या इस तथ्य से भी संबंधित हो सकती है कि समांतर। स्पष्ट रूप से मुख्य थ्रेड (कम से कम उदाहरण कोड में, लिखित रूप में) के रूप में "कार्यकर्ता धागे" (या जो कुछ भी उन्हें बुलाया जाना चाहिए) समांतर डोमेन)। जब भी DoLongRunningWork निष्पादित किया जाता है, तो एक नया लॉजिकल ऑपरेशन शुरू होता है (शुरुआत में) और बंद हो जाता है (अंत में) (यानी, लॉजिकलऑपरेशनस्टैक पर धक्का दिया जाता है और इसके पीछे से पॉप किया जाता है)। यदि मुख्य धागे में पहले से ही एक तार्किक ऑपरेशन है और यदि डॉन लोंगरिंग वर्क मुख्य थ्रेड पर निष्पादित करता है, तो एक नया लॉजिकल ऑपरेशन शुरू हो गया है, इसलिए मुख्य थ्रेड के लॉजिकलऑपरेशनस्टैक में अब दो ऑपरेशन हैं। DoLongRunningWork के किसी भी बाद के निष्पादन (जब तक DoLongRunningWork का यह "पुनरावृत्ति" मुख्य धागे पर निष्पादित हो रहा है) (जाहिर है) मुख्य थ्रेड के लॉजिकलऑपरेशनस्टैक (जो अब केवल एक अपेक्षित ऑपरेशन के बजाए दो ऑपरेशन है) का वारिस करेगा।
यह मुझे एक लंबे समय यह पता लगाने की क्यों LogicalOperationStack का व्यवहार आपके उदाहरण के अपने संशोधित संस्करण की तुलना में मेरे उदाहरण में अलग था ले लिया। आखिरकार मैंने देखा कि मेरे कोड में मैंने पूरे कार्यक्रम को लॉजिकल ऑपरेशन में ब्रैकेट किया था, जबकि आपके टेस्ट प्रोग्राम के मेरे संशोधित संस्करण में मैंने नहीं किया था। निहितार्थ यह है कि मेरे परीक्षण कार्यक्रम में, हर बार जब मेरा "काम" किया गया था (DoLongRunningWork के समान), पहले से ही एक तार्किक ऑपरेशन प्रभावी था। आपके परीक्षण कार्यक्रम के मेरे संशोधित संस्करण में, मैंने पूरे कार्यक्रम को लॉजिकल ऑपरेशन में ब्रैकेट नहीं किया था।
तो, जब मैं अपने परीक्षण कार्यक्रम एक तार्किक आपरेशन में और अगर मैं Parallel.For उपयोग कर रहा हूँ पूरे कार्यक्रम ब्रैकेट करने के लिए संशोधित, मैं बिल्कुल वैसा ही समस्या हुई थी।
ऊपर वैचारिक मॉडल का उपयोग करना, यह सफलतापूर्वक चलेंगे:
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 साथ इस्तेमाल किया जा सकता इस पूरे मुद्दे (और/या अन्य सूत्रण/टास्क निर्माण करती है) या कैसे यह शायद गुण अपने आप ही सवाल किया जा सकता है। शायद मैं एक प्रश्न पोस्ट करूंगा। इस बीच, मुझे आश्चर्य है कि क्या आपके पास इस पर कोई विचार है (या, मुझे आश्चर्य है कि आपने लॉजिकलऑपरेशनस्टैक का उपयोग करने पर विचार किया था क्योंकि गतिविधि आईडी सुरक्षित होने लगती है)।
[संपादित करें]
विभिन्न धागा/ThreadPool/कार्य/समानांतर contstructs से कुछ के साथ LogicalOperationStack और/या CallContext.LogicalSetData उपयोग के बारे में अधिक जानकारी के लिए this question को मेरा उत्तर देखें।
भी मेरे सवाल का यहाँ देखें अतः LogicalOperationStack और समानांतर एक्सटेंशन के बारे में पर: http://social.msdn.microsoft.com/Forums/en-US/parallelextensions/thread/7c5c3051-133b-4814-9db0-fc0039b4f9d9
मेरी परीक्षण यह ट्रेस की तरह लग रहा है: Is CorrelationManager.LogicalOperationStack compatible with Parallel.For, Tasks, Threads, etc
अंत में, यह भी मेरे सवाल का माइक्रोसॉफ्ट के समानांतर एक्सटेंशन फ़ोरम पर यहाँ देखें। CorrelationManager.LogicalOperationStack समानांतर का उपयोग करते समय दूषित हो सकता है। या समानांतर। इन्वोक यदि आप मुख्य थ्रेड में लॉजिकल ऑपरेशन प्रारंभ करते हैं और फिर प्रतिनिधि में लॉजिकल ऑपरेशंस प्रारंभ/बंद करते हैं। मेरे परीक्षणों में (ऊपर दिए गए दो लिंक में से किसी एक को देखें) LogicalOperationStack में हमेशा 2 प्रविष्टियां होनी चाहिए जब DoLongRunningWork निष्पादित हो रहा है (यदि मैं विभिन्न तकनीकों का उपयोग करके DoLongRunningWork को लात मारने से पहले मुख्य धागे में लॉजिकल ऑपरेशन शुरू करता हूं)। तो, "दूषित" से मेरा मतलब है कि लॉजिकलऑपरेशनस्टैक में अंततः 2 से अधिक प्रविष्टियां होंगी।
जो मैं कह सकता हूं उससे, शायद यह है क्योंकि समांतर। फॉर और समानांतर। इनवोक मुख्य थ्रेड का उपयोग "कार्यकर्ता" धागे में से एक के रूप में DoLongRunningWork कार्रवाई करने के लिए करता है।
LogicalOperationStack के व्यवहार की नकल करने के लिए CallContext.LogicalSetData में संग्रहीत एक स्टैक का उपयोग करना (Log4net के लॉजिकल थ्रेड कॉन्टेक्स्ट.स्टैक के समान जो कॉलकॉन्टेक्स्ट.SetData के माध्यम से संग्रहीत है) भी इससे भी बदतर परिणाम उत्पन्न करता है। यदि मैं संदर्भ बनाए रखने के लिए इस तरह के ढेर का उपयोग कर रहा हूं, तो यह लगभग सभी परिदृश्यों में दूषित हो जाता है (यानी प्रविष्टियों की अपेक्षित संख्या नहीं है) जहां मेरे पास मुख्य धागे में "लॉजिकल ऑपरेशन" है और प्रत्येक पुनरावृत्ति में लॉजिकल ऑपरेशन है/DoLongRunningWork प्रतिनिधि के निष्पादन।
मेरे पास प्रस्ताव देने के लिए कुछ भी नहीं है, लेकिन मुझे इस मुद्दे में भी रूचि है। ऐसा लगता है कि वही प्रश्न सामान्य रूप से CallContext.LogicalSetData का उपयोग करके सूचना सेट पर भी लागू होता है क्योंकि यह तकनीक है जो Trace.CorrelationManager गतिविधि आईडी और लॉजिकलऑपरेशनस्टैक को संग्रहीत करने के लिए उपयोग करती है। – wageoghe
@wageohe - मैं अंत में आज परीक्षण करने के लिए चारों ओर मिल गया, मेरे परिणाम पोस्ट कर दिया है :) –
मैंने अपने उत्तर में कुछ और विवरण पोस्ट किए हैं। मैंने एसओ पर एक और उत्तर के लिए एक लिंक भी पोस्ट किया, एक नया सवाल जिसे मैंने यहां एसओ पर पूछा था, साथ ही साथ एक प्रश्न जो मैंने पूछा (लेकिन अभी तक 1/21/2011 के रूप में उत्तर नहीं दिया गया है) माइक्रोसॉफ्ट के समांतर एक्सटेंशन फोरम पर । शायद आपको जानकारी उपयोगी लगेगी, शायद नहीं। – wageoghe