में किसी निश्चित दर पर फ़ाइल पढ़ें, क्या कोई लेख/एल्गोरिदम है कि मैं एक निश्चित दर पर एक लंबी फ़ाइल कैसे पढ़ सकता हूं?जावा
कहें कि मैं पढ़ना जारी करते समय 10 केबी/सेकंड पास नहीं करना चाहता हूं।
में किसी निश्चित दर पर फ़ाइल पढ़ें, क्या कोई लेख/एल्गोरिदम है कि मैं एक निश्चित दर पर एक लंबी फ़ाइल कैसे पढ़ सकता हूं?जावा
कहें कि मैं पढ़ना जारी करते समय 10 केबी/सेकंड पास नहीं करना चाहता हूं।
कच्चे समाधान सिर्फ एक समय में एक हिस्सा पढ़ने के लिए है और फिर सो जाओ जैसे 10k फिर एक सेकंड सो जाओ। लेकिन मुझे पहले सवाल पूछना है: क्यों? कुछ संभावित उत्तर हैं:
मेरा सुझाव इसे पढ़ने के स्तर पर नियंत्रित नहीं करना है। वह गन्दा और गलत है। इसके बजाय काम के अंत में इसे नियंत्रित करें। इस से निपटने के लिए जावा में बहुत सारे समेकन उपकरण हैं। ऐसा करने के कुछ वैकल्पिक तरीके हैं।
मुझे इस तरह की समस्या को हल करने के लिए producer consumer पैटर्न का उपयोग करना पसंद है। यह आपको रिपोर्टिंग थ्रेड करके प्रगति की निगरानी करने में सक्षम होने पर बहुत अच्छा विकल्प देता है और इसी तरह और यह वास्तव में एक साफ समाधान हो सकता है।
कुछ ArrayBlockingQueue की तरह कुछ (1) और (2) दोनों के लिए आवश्यक थ्रॉटलिंग के लिए उपयोग किया जा सकता है। सीमित क्षमता के साथ जब कतार पूरी हो जाती है तो पाठक अंततः अवरुद्ध हो जाता है, इसलिए बहुत तेज नहीं होगा। मजदूरों (उपभोक्ताओं) को केवल कवर करने के लिए नियंत्रित किया जा सकता है ताकि दर कवर (2) को भी कम किया जा सके।
यह इस बात पर थोड़ा निर्भर करता है कि क्या आपका मतलब है "एक निश्चित दर से अधिक न हो" या "किसी निश्चित दर के करीब रहें।"
यदि आप मतलब है "से अधिक नहीं है", आप एक सरल पाश के साथ कि गारंटी ले सकते हैं:
while not EOF do
read a buffer
Thread.wait(time)
write the buffer
od
समय तक इंतजार करना की राशि बफर के आकार का एक सरल कार्य है; यदि बफर आकार 10 के बाइट्स है, तो आप पढ़ने के बीच एक सेकंड प्रतीक्षा करना चाहते हैं।
यदि आप उससे अधिक करीब जाना चाहते हैं, तो आपको शायद टाइमर का उपयोग करने की आवश्यकता है।
यदि आप उस गति के बारे में चिंतित हैं जिस पर आप कुछ और करने के लिए डेटा पास कर रहे हैं, तो पढ़ने को नियंत्रित करने के बजाय, डेटा को डेटा संरचना जैसे कतार या परिपत्र बफर में रखें, और उसे नियंत्रित करें दूसरा अंत; समय-समय पर डेटा भेजें। हालांकि, डेटा सेट आकार और इस तरह के आधार पर आपको सावधान रहना होगा, क्योंकि पाठक लेखक की तुलना में बहुत तेज़ है, तो आप मेमोरी सीमाओं में भाग सकते हैं।
यदि आपने जावा I/O का उपयोग किया है तो आपको सजावटी धाराओं से परिचित होना चाहिए। मैं एक InputStream
सबक्लास का सुझाव देता हूं जो InputStream
लेता है और प्रवाह दर को थ्रॉटल करता है। (आप FileInputStream
उपclass कर सकते हैं लेकिन यह दृष्टिकोण अत्यधिक त्रुटि-प्रवण और लचीला है।)
आपका सटीक कार्यान्वयन आपकी सटीक आवश्यकताओं पर निर्भर करेगा। आम तौर पर आप उस समय को नोट करना चाहेंगे जब आपका अंतिम पठन लौटाया जाएगा (System.nanoTime
)। वर्तमान पढ़ने पर, अंतर्निहित पढ़ने के बाद, wait
जब तक स्थानांतरित डेटा की मात्रा के लिए पर्याप्त समय बीत चुका नहीं जाता है। एक अधिक परिष्कृत कार्यान्वयन बफर और वापसी (लगभग) तुरंत डेटा के अनुसार जितना अधिक डेटा हो सकता है (सावधान रहें कि यदि बफर शून्य की लंबाई है तो आपको केवल 0 की पढ़ाई लंबाई वापस करनी चाहिए)।
थ्रॉटलड इनपुटस्ट्रीम बनाना जो सुझाए गए एक और इनपुटस्ट्रीम को एक अच्छा समाधान होगा।
थ्रॉटलड इनपुटस्ट्रीम बनाकर एक साधारण समाधान।
यह इस तरह इस्तेमाल किया जाना चाहिए:
final InputStream slowIS = new ThrottledInputStream(new BufferedInputStream(new FileInputStream("c:\\file.txt"),8000),300);
300 किलोबाइट प्रति सेकंड की संख्या है। 8000 BufferedInputStream के लिए ब्लॉक आकार है।
यह निश्चित रूप से पढ़ने (बाइट बी [], int off, int len) को लागू करके सामान्यीकृत किया जाना चाहिए, जो आपको System.currentTimeMillis() कॉल का एक टन छोड़ देगा। System.currentTimeMillis() को प्रत्येक बाइट पढ़ने के लिए एक बार बुलाया जाता है, जो ओवरहेड का थोड़ा सा कारण बन सकता है। System.currentTimeMillis() को कॉल किए बिना पढ़ा जा सकता है कि बाइट्स की संख्या को स्टोर करना भी संभव होना चाहिए।
BufferedInputStream को बीच में रखना सुनिश्चित करें, अन्यथा FileInputStream को ब्लॉक के बजाए एकल बाइट्स में मतदान किया जाएगा। इससे CPU लोड फॉर्म 10% से लगभग 0 हो जाएगा। आपको ब्लॉक आकार में बाइट्स की संख्या से डेटा दर से अधिक होने का जोखिम होगा।
import java.io.InputStream;
import java.io.IOException;
public class ThrottledInputStream extends InputStream {
private final InputStream rawStream;
private long totalBytesRead;
private long startTimeMillis;
private static final int BYTES_PER_KILOBYTE = 1024;
private static final int MILLIS_PER_SECOND = 1000;
private final int ratePerMillis;
public ThrottledInputStream(InputStream rawStream, int kBytesPersecond) {
this.rawStream = rawStream;
ratePerMillis = kBytesPersecond * BYTES_PER_KILOBYTE/MILLIS_PER_SECOND;
}
@Override
public int read() throws IOException {
if (startTimeMillis == 0) {
startTimeMillis = System.currentTimeMillis();
}
long now = System.currentTimeMillis();
long interval = now - startTimeMillis;
//see if we are too fast..
if (interval * ratePerMillis < totalBytesRead + 1) { //+1 because we are reading 1 byte
try {
final long sleepTime = ratePerMillis/(totalBytesRead + 1) - interval; // will most likely only be relevant on the first few passes
Thread.sleep(Math.max(1, sleepTime));
} catch (InterruptedException e) {//never realized what that is good for :)
}
}
totalBytesRead += 1;
return rawStream.read();
}
}
FYI : बाधित अपवाद यह सुनिश्चित करना है कि थ्रेड तुरंत एक बाधा अनुरोध के जवाब दे, भले ही वह सो रहा हो। – Simiil
आप एक रेटलिमीटर का उपयोग कर सकते हैं। और इनपुटस्ट्रीम में पढ़ने का अपना कार्यान्वयन करें। इस का एक उदाहरण bellow
public class InputStreamFlow extends InputStream {
private final InputStream inputStream;
private final RateLimiter maxBytesPerSecond;
public InputStreamFlow(InputStream inputStream, RateLimiter limiter) {
this.inputStream = inputStream;
this.maxBytesPerSecond = limiter;
}
@Override
public int read() throws IOException {
maxBytesPerSecond.acquire(1);
return (inputStream.read());
}
@Override
public int read(byte[] b) throws IOException {
maxBytesPerSecond.acquire(b.length);
return (inputStream.read(b));
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
maxBytesPerSecond.acquire(len);
return (inputStream.read(b,off, len));
}
}
देखा जा सकता है अगर आप 1 एमबी से प्रवाह को सीमित करना चाहते/s आप इस तरह इनपुट स्ट्रीम प्राप्त कर सकते हैं:
final RateLimiter limiter = RateLimiter.create(RateLimiter.ONE_MB);
final InputStreamFlow inputStreamFlow = new InputStreamFlow(originalInputStream, limiter);
सवाल तुम क्यों चाहेगा है करने के लिए एक निश्चित दर पर एक फाइल पढ़ें? लगता है जैसे आप मांग पर डेटा पढ़ना चाहते हैं, इस प्रकार आपकी "मांग" को समझने से हम आपको बेहतर समाधान के लिए इंगित कर सकते हैं। – EFraim
मैं इंटरनेट से एक बड़ी फाइल डाउनलोड करने जा रहा हूं लेकिन मैं नहीं चाहता कि मेरा एप्लिकेशन उपयोगकर्ता सेट सीमा पास करे। –
https://svn.apache.org/repos/asf/hadoop/common/trunk/hadoop-tools/hadoop-distcp/src/main/java/org/apache/hadoop/tools/util/ThrottledInputStream.java – pvllnspk