मैं मल्टी-थ्रेडिंग के लिए @threads का उपयोग करके नीचे दिए गए कोड for loop को चलाने की कोशिश कर रहा हूं, हालांकि परिणाम हमेशा आउटपुट की बेमेल संख्या की त्रुटि को चित्रित करते हैं।

using Combinatorics, Base.Threads
import Base.Threads.@threads
func(x, y)
result = Float64[]
a = Float64[]
@threads for c in combinations(1:n, 2)
        a, b = c
        result = func(a, b)
        push!(result, result)
        push!(a, a)     
     end

प्रसंस्करण के दौरान देखी गई त्रुटि:

DimensionMismatch("column :result has length 60 and column :a has length 50")

कृपया एक दृष्टिकोण सुझाएं जो सुनिश्चित करें कि लूप से कोई उत्परिवर्तन छूट न जाए।

1
Mohammad Saad 14 जिंदा 2021, 09:16
1
आपके उदाहरण में कई समस्याएं हैं: स्पष्ट नाम टकराव को अलग रखना (वैश्विक a बनाम स्थानीय a, वैश्विक result बनाम स्थानीय result), Combinatorics.combinations` एक वस्तु उत्पन्न करता है जिस पर मुझे नहीं लगता कि Base.threads पुनरावृति करना जानता है। इसलिए मुझे आश्चर्य है कि आप उस बिंदु तक कैसे पहुंचे जहां दौड़ की स्थिति होगी।
 – 
François Févotte
14 जिंदा 2021, 11:23
1
साथ ही, जब आप अपने प्रश्न के शीर्षक में "I/O संचालन" का उल्लेख करते हैं, तो क्या आप वास्तव में अपने वैक्टर पर push! संचालन का जिक्र कर रहे हैं? यदि हां, तो ये I/O नहीं हैं, बल्कि उत्परिवर्तन हैं
 – 
François Févotte
14 जिंदा 2021, 11:24
सुधार के लिए धन्यवाद, मैंने शीर्षक को म्यूटेशन में बदल दिया है।
 – 
Mohammad Saad
14 जिंदा 2021, 13:22
@ FrançoisFévotte, प्रतिक्रिया के लिए धन्यवाद, मैं सुझाव के अनुसार कोड को हल करने का प्रयास करूंगा और सही दृष्टिकोण मिलने के बाद अपडेट करूंगा।
 – 
Mohammad Saad
14 जिंदा 2021, 13:26

1 उत्तर

सबसे बढ़िया उत्तर

एक बात जो आपके उदाहरण में काम नहीं करती है, वह यह है कि सभी धागे (के माध्यम से push!) एक ही वैक्टर (result और a) को संभवतः समवर्ती रूप से उत्परिवर्तित कर रहे हैं, जिससे दौड़ की स्थिति होने की अनुमति।

इसका एक तरीका यह होगा कि वैक्टरों का संग्रह (एक प्रति धागा); प्रत्येक थ्रेड केवल अपने स्वयं के वेक्टर को संशोधित करता है (इसके द्वारा पहचाना जाता है threadid())।

ऐसी तकनीक के साथ, आपके उदाहरण का एक सरलीकृत संस्करण इस तरह दिख सकता है:

# The function we want to apply to each element
julia> f(x) = 2x+1
f (generic function with 1 method)

# Two collections of vectors (one vector for each thread)
# that will hold the results for each thread
julia> results = [Float64[] for _ in 1:Threads.nthreads()];
julia> as      = [Float64[] for _ in 1:Threads.nthreads()]
8-element Vector{Vector{Float64}}:
 []
 []
 []
 []
 []
 []
 []
 []

julia> Threads.@threads for a in 1:10
           result = f(a)

           # Each thread only ever mutates its own result vector: 
           #    results[Threads.threadid()]
           push!(results[Threads.threadid()], result)
           push!(as[Threads.threadid()],      a)
       end

ध्यान दें कि आपको परिणामों का एक संग्रह मिलेगा, जो उन्हें उत्पन्न करने वाले धागे की आईडी द्वारा अनुक्रमित किया जाएगा।

# Now you get a collection of results, indexed by the id of the thread which produced them
julia> results
8-element Vector{Vector{Float64}}:
 [3.0, 5.0]  # These results have been produced by thread #1
 [7.0, 9.0]
 [11.0]
 [13.0]
 [15.0]
 [17.0]
 [19.0]
 [21.0]

julia> as
8-element Vector{Vector{Float64}}:
 [1.0, 2.0]
 [3.0, 4.0]
 [5.0]
 [6.0]
 [7.0]
 [8.0]
 [9.0]
 [10.0]

अंत में, आपको सभी थ्रेड-विशिष्ट परिणामों को एक में संयोजित करने के लिए सभी परिणामी वैक्टर को किसी तरह से जोड़ना या समतल करना होगा। एक तरीका सभी परिणामों को जोड़ना होगा (जो सभी परिणामों को पकड़ने के लिए एक नया, बड़ा वेक्टर आवंटित करेगा):

julia> reduce(vcat, results)
10-element Vector{Float64}:
  3.0
  5.0
  7.0
  9.0
 11.0
 13.0
 15.0
 17.0
 19.0
 21.0

julia> reduce(vcat, as)
10-element Vector{Float64}:
  1.0
  2.0
  3.0
  4.0
  5.0
  6.0
  7.0
  8.0
  9.0
 10.0

एक और तरीका सीधे नेस्टेड परिणामों पर फिर से शुरू करना होगा, उन्हें फ्लाई पर फ़्लैट करना (ताकि उन्हें एक फ्लैट फैशन में स्टोर करने के लिए डबल मेमोरी आवंटित न करें):

julia> using Base.Iterators: flatten

julia> for r in flatten(results)
           println(r)
       end
3.0
5.0
7.0
9.0
11.0
13.0
15.0
17.0
19.0
21.0

julia> for (a, r) in zip(flatten(as), flatten(results))
           println("$a -> $r")
       end
1.0 -> 3.0
2.0 -> 5.0
3.0 -> 7.0
4.0 -> 9.0
5.0 -> 11.0
6.0 -> 13.0
7.0 -> 15.0
8.0 -> 17.0
9.0 -> 19.0
10.0 -> 21.0
2
François Févotte 14 जिंदा 2021, 11:20
विस्तृत विवरण के लिए धन्यवाद @ FrançoisFévotte, अत्यधिक सराहना !! मैंने इस दृष्टिकोण की कोशिश की है और यह काम करता है।
 – 
Mohammad Saad
18 जिंदा 2021, 11:24