اختناق استخدام وحدة المعالجة المركزية/الذاكرة لسلسلة رسائل في Java؟

StackOverflow https://stackoverflow.com/questions/1202184

سؤال

أنا أكتب تطبيقًا سيحتوي على عدة سلاسل رسائل قيد التشغيل، وأريد تقليل استخدام وحدة المعالجة المركزية/الذاكرة لتلك الخيوط.

هناك سؤال مماثل لC++, ، لكني أريد أن أحاول تجنب استخدام C++ وJNI إن أمكن.أدرك أن هذا قد لا يكون ممكنًا باستخدام لغة ذات مستوى أعلى، ولكن لدي فضول لمعرفة ما إذا كان لدى أي شخص أي أفكار.

يحرر: تمت إضافة مكافأة.أريد بعض الأفكار الجيدة والمدروسة جيدًا في هذا الشأن.

تحرير 2: الموقف الذي أحتاج إليه هو تنفيذ تعليمات برمجية خاصة بأشخاص آخرين على الخادم الخاص بي.إنه في الأساس رمز تعسفي تمامًا، مع الضمان الوحيد بأنه ستكون هناك طريقة رئيسية في ملف الفئة.حاليًا، يتم تنفيذ عدة فئات متباينة تمامًا، والتي يتم تحميلها في وقت التشغيل، بشكل متزامن كسلاسل منفصلة.

الطريقة التي تمت كتابتها بها، سيكون من الصعب إعادة البناء لإنشاء عمليات منفصلة لكل فئة يتم تنفيذها.إذا كانت هذه هي الطريقة الجيدة الوحيدة للحد من استخدام الذاكرة عبر وسائط VM، فليكن.ولكن أود أن أعرف إذا كان هناك طريقة للقيام بذلك مع المواضيع.حتى كعملية منفصلة، ​​أود أن أكون قادرًا بطريقة أو بأخرى على الحد من استخدام وحدة المعالجة المركزية الخاصة بها، لأنه كما ذكرت سابقًا، سيتم تنفيذ العديد من هذه العمليات في وقت واحد.لا أريد حلقة لا نهائية لاستنزاف جميع الموارد.

تحرير 3: هناك طريقة سهلة لتقريب حجم الكائن باستخدام Java الأجهزة الطبقات؛على وجه التحديد، طريقة getObjectSize.لاحظ أن هناك بعض الإعدادات الخاصة اللازمة لاستخدام هذه الأداة.

هل كانت مفيدة؟

المحلول

إذا فهمت مشكلتك، فإن إحدى الطرق هي وضع المواضيع في وضع السكون بشكل تكيفي، تمامًا كما يتم تشغيل الفيديو في Java.إذا كنت تعلم أنك تريد استخدامًا أساسيًا بنسبة 50%، فيجب أن تكون الخوارزمية الخاصة بك في وضع السكون لمدة 0.5 ثانية تقريبًا - ومن المحتمل أن يتم توزيعها خلال ثانية واحدة (على سبيل المثال.حساب 0.25 ثانية، 0.25 ثانية نوم، وما إلى ذلك).هنا مثال من مشغل الفيديو الخاص بي.

long starttime = 0; // variable declared
//...
// for the first time, remember the timestamp
if (frameCount == 0) {
    starttime = System.currentTimeMillis();
}
// the next timestamp we want to wake up
starttime += (1000.0 / fps);
// Wait until the desired next time arrives using nanosecond
// accuracy timer (wait(time) isn't accurate enough on most platforms) 
LockSupport.parkNanos((long)(Math.max(0, 
    starttime - System.currentTimeMillis()) * 1000000));

سوف ينام هذا الرمز بناءً على الإطارات/القيمة الثانية.

لتقييد استخدام الذاكرة، يمكنك لف إنشاء الكائن الخاص بك بطريقة المصنع، واستخدام نوع من الإشارة مع تصاريح محدودة كبايت للحد من إجمالي حجم الكائن المقدر (تحتاج إلى تقدير حجم الكائنات المختلفة لتقييد الإشارة ).

package concur;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class MemoryLimited {
    private static Semaphore semaphore = new Semaphore(1024 * 1024, true);
    // acquire method to get a size length array
    public static byte[] createArray(int size) throws InterruptedException {
        // ask the semaphore for the amount of memory
        semaphore.acquire(size);
        // if we get here we got the requested memory reserved
        return new byte[size];
    }
    public static void releaseArray(byte[] array) {
        // we don't need the memory of array, release
        semaphore.release(array.length);
    }
    // allocation size, if N > 1M then there will be mutual exclusion
    static final int N = 600000;
    // the test program
    public static void main(String[] args) {
        // create 2 threaded executor for the demonstration
        ExecutorService exec = Executors.newFixedThreadPool(2);
        // what we want to run for allocation testion
        Runnable run = new Runnable() {
            @Override
            public void run() {
                Random rnd = new Random();
                // do it 10 times to be sure we get the desired effect
                for (int i = 0; i < 10; i++) {
                    try {
                        // sleep randomly to achieve thread interleaving
                        TimeUnit.MILLISECONDS.sleep(rnd.nextInt(100) * 10);
                        // ask for N bytes of memory
                        byte[] array = createArray(N);
                        // print current memory occupation log
                        System.out.printf("%s %d: %s (%d)%n",
                            Thread.currentThread().getName(),
                            System.currentTimeMillis(), array,
                            semaphore.availablePermits());
                        // wait some more for the next thread interleaving
                        TimeUnit.MILLISECONDS.sleep(rnd.nextInt(100) * 10);
                        // release memory, no longer needed
                        releaseArray(array);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        // run first task
        exec.submit(run);
        // run second task
        exec.submit(run);
        // let the executor exit when it has finished processing the runnables
        exec.shutdown();
    }
}

نصائح أخرى

يمكنك الحصول على الكثير من المعلومات حول استخدام وحدة المعالجة المركزية والذاكرة عبر جمكس, ، لكنني لا أعتقد أنه يسمح بأي تلاعب نشط.

للتحكم في استخدام وحدة المعالجة المركزية إلى حد ما، يمكنك استخدام Thread.setPriority().

أما بالنسبة للذاكرة، فلا يوجد شيء اسمه ذاكرة لكل خيط.إن مفهوم سلاسل Java ذاته يعني الذاكرة المشتركة.الطريقة الوحيدة للتحكم في استخدام الذاكرة هي عبر خيارات سطر الأوامر مثل -Xmx، ولكن لا توجد طريقة لمعالجة الإعدادات في وقت التشغيل.

يعتني ب منتديات جافا.قم بتوقيت تنفيذك بشكل أساسي ثم الانتظار عندما تستغرق الكثير من الوقت.كما هو مذكور في سلسلة المحادثات الأصلية، فإن تشغيل هذا في سلسلة منفصلة ومقاطعة سلسلة العمل سيعطي نتائج أكثر دقة، وكذلك متوسط ​​القيم بمرور الوقت.

import java.lang.management.*;

ThreadMXBean TMB = ManagementFactory.getThreadMXBean();
long time = new Date().getTime() * 1000000;
long cput = 0;
double cpuperc = -1;

while(true){

if( TMB.isThreadCpuTimeSupported() ){
    if(new Date().getTime() * 1000000 - time > 1000000000){ //Reset once per second
        time = new Date().getTime() * 1000000;
        cput = TMB.getCurrentThreadCpuTime();
    }

    if(!TMB.isThreadCpuTimeEnabled()){
        TMB.setThreadCpuTimeEnabled(true);
    }

    if(new Date().getTime() * 1000000 - time != 0)
        cpuperc = (TMB.getCurrentThreadCpuTime() - cput) / (new Date().getTime() *  1000000.0 - time) * 100.0;                  
    }
//If cpu usage is greater then 50%
if(cpuperc > 50.0){
     //sleep for a little bit.
     continue;
}
//Do cpu intensive stuff
}

يمكنك تعيين أولويات مختلفة لسلاسل الرسائل بحيث تتم جدولة سلسلة المحادثات الأكثر صلة في كثير من الأحيان.

أنظر إلى هذا إجابة لمعرفة ما إذا كان ذلك يساعد.

عندما يكون لكل الخيوط الجاري تشغيلها نفس الأولوية، فقد يتم تشغيلها على النحو التالي:

t1, t2, t3,     t1, t2, t3,   t1, t2, t3

عندما تقوم بتعيين أولوية مختلفة لأحدهم قد يبدو الأمر كما يلي:

t1, t1, t1, t1,    t2,    t1, t1, t1 t3.

وهذا يعني أن الخيط الأول يعمل "في كثير من الأحيان" أكثر من الباقي.

إذا قمت بتشغيل سلاسل الرسائل في عملية منفصلة، ​​فيمكنك تحديد استخدام الذاكرة وتحديد عدد وحدات المعالجة المركزية (CPUs) أو تغيير أولوية هذه الخيوط.

ومع ذلك، فإن أي شيء تفعله من المرجح أن يزيد من النفقات العامة والتعقيد، وهو ما يؤدي غالبًا إلى نتائج عكسية.

ما لم تتمكن من شرح سبب رغبتك في القيام بذلك (على سبيل المثال:لديك مكتبة مكتوبة بشكل سيء ولا تثق بها ولا يمكنك الحصول على الدعم لها) أود أن أقترح أنك لست بحاجة إلى ذلك.

السبب وراء صعوبة تقييد استخدام الذاكرة هو وجود كومة واحدة فقط تتم مشاركتها.لذا فإن الكائن الذي يتم استخدامه في مؤشر ترابط واحد يكون قابلاً للاستخدام في مؤشر ترابط آخر ولا يتم تعيينه لمؤشر ترابط واحد أو آخر.

إن الحد من استخدام وحدة المعالجة المركزية يعني إيقاف جميع الخيوط حتى لا تفعل أي شيء، ولكن الطريقة الأفضل هي التأكد من أن الخيوط لا تهدر وحدة المعالجة المركزية وأنها نشطة فقط في أداء العمل الذي يجب القيام به، وفي هذه الحالة لن تفعل ذلك تريد منعهم من القيام بذلك.

لماذا لا تقوم بمهام متعددة تعاونية بدلاً من القيام بـ "الترابط"، سيكون من المثير للاهتمام معرفة ما إذا كان بإمكانك التلاعب بها http://www.janino.net/ لتشغيل برنامج لفترة معينة من الوقت/مجموعة التعليمات، ثم إيقاف البرنامج التالي وتشغيله.على الأقل بهذه الطريقة يكون الأمر عادلاً، أعط الجميع نفس الوقت...

قد يساعدك Thread.setPriority()، لكنه لا يسمح لك بوضع حد أقصى لوحدة المعالجة المركزية التي يستخدمها مؤشر ترابط.في الواقع، لم أسمع عن أي مكتبة جافا تقوم بذلك.

قد يكون من الممكن تنفيذ مثل هذه التسهيلات بشرط أن تكون سلاسل الرسائل الخاصة بك مستعدة للتعاون.المفتاح هو استدعاء سلاسل الرسائل بشكل دوري إلى برنامج جدولة مخصص، وجعل جهاز الجدولة يراقب استخدام وحدة المعالجة المركزية لمؤشر الترابط باستخدام JMX.لكن المشكلة تكمن في أنه إذا لم يقم بعض سلاسل العمليات بإجراء استدعاء المجدول بشكل كافٍ، فقد يتجاوز حدود التقييد.وليس هناك ما يمكنك فعله بشأن الخيط الذي يعلق في حلقة ما.

هناك طريق نظري آخر للتنفيذ وهو استخدام العزلات.لسوء الحظ، سيكون من الصعب عليك العثور على JVM للأغراض العامة الذي ينفذ العزلات.علاوة على ذلك، تسمح لك واجهات برمجة التطبيقات القياسية فقط بالتحكم في العزل، وليس الخيوط الموجودة داخل العزل.

الطريقة الوحيدة التي يمكنك من خلالها الحد من استخدام وحدة المعالجة المركزية لمؤشر الترابط هي إما حظر أحد الموارد أو استدعاء العائد () بشكل متكرر.

هذا لا يحد من استخدام وحدة المعالجة المركزية أقل من 100% ولكنه يمنح مؤشرات الترابط والعمليات الأخرى المزيد من الشرائح الزمنية.

لتقليل وحدة المعالجة المركزية، فأنت تريد أن تضع خيوطك في وضع السكون داخل ملف common لو و بينما حلقات.

while(whatever) {
    //do something
    //Note the capitol 'T' here, this sleeps the current thread.
    Thread.sleep(someNumberOfMilliSeconds);
}

سيؤدي النوم لبضع مئات من المللي ثانية إلى تقليل استخدام وحدة المعالجة المركزية بشكل كبير مع تأثير ضئيل أو معدوم على الأداء.

أما بالنسبة للذاكرة، فسوف أقوم بتشغيل ملف التعريف على المواضيع الفردية وإجراء بعض ضبط الأداء.إذا قمت بتقليص مقدار الذاكرة المتوفرة لمؤشر الترابط، فأعتقد أنه من المحتمل أن يكون هناك استثناء نفاد الذاكرة أو مؤشر ترابط متعطش.أثق في JVM لتوفير أكبر قدر ممكن من الذاكرة التي يحتاجها مؤشر الترابط والعمل على تقليل استخدام الذاكرة عن طريق الاحتفاظ بالكائنات الأساسية فقط في النطاق في أي وقت محدد.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top