2010-06-12 13 views
40

print पायथन में thesearticles के अनुसार थ्रेड सुरक्षित नहीं है।मुझे पायथन 2.6 में थ्रेड सुरक्षित प्रिंट कैसे प्राप्त किया जा सकता है?

बाद वाले लेख में एक पायथन 3 कार्य-आसपास की पेशकश की जाती है।

मैं पाइथन 2.6 में print को थ्रेड सुरक्षित कैसे प्राप्त करूं?

+0

उन लेखों पायथन 3. के बारे में हैं कहाँ लेख करते हुए कहा कि 'पायथन 2.x में print' हैं धागा सुरक्षित नहीं है? –

+3

इग्नासिओ: मैंने इसे स्वयं देखा है :-) स्टडआउट पर प्रिंट करने वाले कुछ धागे को कताई करने का प्रयास करें। लाइनों को सब गड़बड़ कर दिया जाएगा। – knorv

उत्तर

34

दिलचस्प समस्या - print कथन के भीतर होने वाली सभी चीजों पर विचार करते हुए, softspace विशेषता की सेटिंग और जांच सहित, इसे "थ्रेडसेफ" (अर्थात्: वास्तव में: थ्रेड जो केवल प्रिंटिंग करता है "मानक आउटपुट का नियंत्रण "जब यह एक नई लाइन प्रिंट कर रहा है, तो एक और थ्रेड के लिए, ताकि आउटपुट की प्रत्येक पंक्ति को एक थ्रेड से आने की गारंटी दी जा सके) एक चुनौती थी (वास्तविक थ्रेड सुरक्षा के लिए सामान्य आसान दृष्टिकोण - एक अलग थ्रेड को प्रस्तुत करना विशेष रूप से "स्वयं" और sys.stdout को संभालें, क्यूई के माध्यम से इसके साथ संवाद करें। क्यूयू - यह सब उपयोगी नहीं है, क्योंकि समस्या थ्रेड सुरक्षा [[सादा print के साथ भी कोई जोखिम नहीं है एफ क्रैशिंग और मानक आउटपुट पर समाप्त होने वाले पात्र बिल्कुल वही हैं जो मुद्रित होते हैं]] लेकिन संचालन की एक विस्तृत श्रृंखला के लिए धागे के बीच पारस्परिक बहिष्कार की आवश्यकता)।

तो, मुझे लगता है कि मैं इसे बनाया ...:

import random 
import sys 
import thread 
import threading 
import time 

def wait(): 
    time.sleep(random.random()) 
    return 'W' 

def targ(): 
    for n in range(8): 
    wait() 
    print 'Thr', wait(), thread.get_ident(), wait(), 'at', wait(), n 

tls = threading.local() 

class ThreadSafeFile(object): 
    def __init__(self, f): 
    self.f = f 
    self.lock = threading.RLock() 
    self.nesting = 0 

    def _getlock(self): 
    self.lock.acquire() 
    self.nesting += 1 

    def _droplock(self): 
    nesting = self.nesting 
    self.nesting = 0 
    for i in range(nesting): 
     self.lock.release() 

    def __getattr__(self, name): 
    if name == 'softspace': 
     return tls.softspace 
    else: 
     raise AttributeError(name) 

    def __setattr__(self, name, value): 
    if name == 'softspace': 
     tls.softspace = value 
    else: 
     return object.__setattr__(self, name, value) 

    def write(self, data): 
    self._getlock() 
    self.f.write(data) 
    if data == '\n': 
     self._droplock() 

# comment the following statement out to get guaranteed chaos;-) 
sys.stdout = ThreadSafeFile(sys.stdout) 

thrs = [] 
for i in range(8): 
    thrs.append(threading.Thread(target=targ)) 
print 'Starting' 
for t in thrs: 
    t.start() 
for t in thrs: 
    t.join() 
print 'Done' 

wait के लिए कॉल गारंटी इस पारस्परिक अपवर्जन गारंटी के अभाव में अस्त व्यस्त मिश्रित निर्गम (टिप्पणी जिस कारण से) करना है। रैपिंग के साथ, यानी उपर्युक्त कोड ठीक उसी तरह दिखता है, और (कम से कम) पायथन 2.5 और ऊपर (मुझे विश्वास है कि यह पिछले संस्करणों में भी चलाया जा सकता है, लेकिन मेरे पास जांचने के लिए आसानी से हाथ नहीं है) उत्पादन होता है:

Thr W -1340583936 W at W 0 
Thr W -1340051456 W at W 0 
Thr W -1338986496 W at W 0 
Thr W -1341116416 W at W 0 
Thr W -1337921536 W at W 0 
Thr W -1341648896 W at W 0 
Thr W -1338454016 W at W 0 
Thr W -1339518976 W at W 0 
Thr W -1340583936 W at W 1 
Thr W -1340051456 W at W 1 
Thr W -1338986496 W at W 1 
    ...more of the same... 

"क्रमबद्धता" efect (जिससे धागे प्रकट करने के लिए "अच्छी तरह से राउंड-रोबिन" के रूप में ऊपर) इस तथ्य का एक पक्ष प्रभाव है कि धागा है कि हो जाता है वर्तमान में मुद्रण हो रहा है एक दूसरों की तुलना में गंभीरता से धीमा है (वे सभी इंतजार कर रहे हैं! -)। wait में time.sleep बाहर टिप्पणी करते हुए उत्पादन के बजाय है

Thr W -1341648896 W at W 0 
Thr W -1341116416 W at W 0 
Thr W -1341648896 W at W 1 
Thr W -1340583936 W at W 0 
Thr W -1340051456 W at W 0 
Thr W -1341116416 W at W 1 
Thr W -1341116416 W at W 2 
Thr W -1338986496 W at W 0 
    ...more of the same... 

अर्थात एक और अधिक विशिष्ट "बहु उत्पादन" ... गारंटी नहीं है कि उत्पादन में प्रत्येक पंक्ति एक ही धागे से पूरी तरह से आता है के लिए छोड़कर।

बेशक, एक थ्रेड जो करता है, उदा।, print 'ciao', मानक आउटपुट के "स्वामित्व" को तब तक रखेगा जब तक कि यह अंततः पीछे की ओर कॉमा के बिना प्रिंट नहीं करता है, और प्रिंट करने के इच्छुक अन्य थ्रेड थोड़ी देर के लिए सो सकते हैं (कैसे कोई गारंटी दे सकता है कि आउटपुट में प्रत्येक पंक्ति आती है एक धागा? ठीक है, एक आर्किटेक्चर मानक आउटपुट में उन्हें वास्तव में लिखने के बजाय थ्रेड स्थानीय स्टोरेज में आंशिक रेखाएं जमा करना होगा, और केवल \n की प्राप्ति पर लेखन करना होगा ... softspace सेटिंग्स के साथ ठीक से इंटरलीव करने के लिए नाज़ुक, मुझे डर है , लेकिन शायद व्यवहार्य)।

13

मुझे नहीं पता कि यह लॉकिंग तंत्र के बजाय कोई बेहतर तरीका है, लेकिन कम से कम यह आसान दिखता है। मुझे यह भी यकीन नहीं है कि प्रिंटिंग वास्तव में धागा सुरक्षित नहीं है।

संपादित करें: ठीक है, अब यह मेरा स्वयं परीक्षण कर रहा है, आप सही हैं, आप वास्तव में चौड़े दिखने वाले आउटपुट प्राप्त कर सकते हैं। और आपको भविष्य आयात की आवश्यकता नहीं है, क्योंकि यह सिर्फ वहां है, क्योंकि मैं पायथन 2.7 का उपयोग करता हूं।

from __future__ import print_function 
from threading import Lock 

print_lock = Lock() 
def save_print(*args, **kwargs): 
    with print_lock: 
    print (*args, **kwargs) 

save_print("test", "omg", sep='lol') 
+1

लॉक [मदद नहीं करता] (http://stackoverflow.com/q/7687862/4279)। – jfs

+0

@ एविलपी: मुझे लगता है कि आप पाइथन 3 का उपयोग कर रहे हैं। उदाहरण के लिए। पायथन 2.7 - 'प्रिंट (" test1 "," test2 ") में वास्तव में' प्रिंट टुपल ("test1", "test2") के रूप में निष्पादित किया जाता है। इसलिए '* args, ** kwargs' पैरामीटर सही नहीं हैं और' print "test1", "test2" के समान नहीं हैं। – Alex

+0

@ एविलपी: ओह, यह ठीक है अन्यथा ठीक काम करता है। ;) – Alex

22

मुद्दा यह है कि पायथन न्यूलाइन प्रिंटिंग और ऑब्जेक्ट की प्रिंटिंग के लिए अलग ऑपोड का उपयोग करता है। सबसे आसान समाधान शायद एक स्पष्ट newline के साथ एक स्पष्ट sys.stdout.write का उपयोग करना है।

+7

मेरे हाल के अनुभव से, यह बिल्कुल सही है। मुझे बिल्कुल यकीन नहीं है कि ऐसा क्यों होता है, लेकिन 'प्रिंट' कथन (यहां तक ​​कि जब STDOUT ठीक से क्रमबद्ध और फ़्लश किया जाता है) अनियमित न्यूलाइन आउटपुट करेगा। इससे बचने के लिए आपको * sys.stdout.write (s + '\ n') 'का उपयोग करना होगा। – efotinis

+6

बस sys.stdout.write का उपयोग एक बहुप्रचारित वातावरण में धारावाहिक आउटपुट की कोई गारंटी नहीं है। आपको लॉक की भी आवश्यकता है। –

13

प्रयोग के माध्यम से, मैंने पाया कि निम्न काम करता है, आसान है, और मेरी जरूरतों सूट:

print "your string here\n", 

या, एक समारोह में लिपटे,

def safe_print(content): 
    print "{0}\n".format(content), 

मेरे समझ है कि निहित न्यू लाइन एक सामान्य print वास्तव में एक अलग ऑपरेशन में stdout करने के लिए आउटपुट है, जिससे अन्य print संचालन के साथ दौड़ की स्थिति उत्पन्न होती है। , के साथ इस अंतर्निहित न्यूलाइन को हटाकर, और स्ट्रिंग में नई लाइन सहित, हम इस समस्या से बच सकते हैं।


2017 संपादित करें: इस जवाब कुछ भाप लेने के लिए शुरू कर रहा है, तो मैं सिर्फ एक स्पष्टीकरण बनाना चाहते थे। यह वास्तव में print "थ्रेड सुरक्षित" वास्तव में नहीं बनाता है। आउटपुट गलत क्रम में हो सकता है यदि print एक दूसरे से अलग माइक्रोसेकंड होता है। यह करता है, हालांकि, समवर्ती धागे से निष्पादित print कथन से आने वाले गड़बड़ आउटपुट से बचने वाला है, जो कि इस प्रश्न पूछने पर ज्यादातर लोग वास्तव में चाहते हैं।

यहाँ दिखाने के लिए मैं क्या मतलब है एक परीक्षण है:

from concurrent.futures import ThreadPoolExecutor 


def normal_print(content): 
    print content 

def safe_print(content): 
    print "{0}\n".format(content), 


with ThreadPoolExecutor(max_workers=10) as executor: 
    print "Normal Print:" 
    for i in range(10): 
     executor.submit(normal_print, i) 

print "---" 

with ThreadPoolExecutor(max_workers=10) as executor: 
    print "Safe Print:" 
    for i in range(10): 
     executor.submit(safe_print, i) 

आउटपुट:

Normal Print: 
0 
1 
23 

4 
65 

7 
9 
8 
---- 
Safe Print: 
1 
0 
3 
2 
4 
5 
6 
7 
8 
9 
+3

दिलचस्प, यह मेरे लिए काम करता है –

+0

यह मेरे लिए भी काम करता है। – nkhuyu

संबंधित मुद्दे