ช่วยให้คุณสามารถผูกเธรดกับคอร์ที่กำหนดได้ สิ่งนี้สามารถปรับปรุงประสิทธิภาพได้ (ไลบรารีนี้ทำงานได้ดีที่สุดบน linux)
ไลบรารี OpenHFT Java Thread Affinity
ดู affinity/src/test/java สำหรับตัวอย่างการทำงานของวิธีใช้ไลบรารีนี้
V3.2.0 - เพิ่มการรองรับสำหรับการกำหนดค่าข้อความ
V3.1.1 - อัปเกรดการพึ่งพา JNA เป็น 4.4.0
V2.0.1 - เพิ่ม getThreadId สำหรับกระบวนการหากของเธรด
Java-Thread-Affinity จะพยายามใช้ JNA เพื่อให้สามารถเข้าถึงฟังก์ชันการจัดการเธรดดั้งเดิม ควรติดตั้ง JNA บนระบบของคุณเพื่อให้ได้รับประโยชน์สูงสุดจากไลบรารีนี้
ปัจจุบัน Java-Thread-Affinity ขึ้นอยู่กับ JNA เวอร์ชัน 4.4.0 ซึ่งจะขึ้นอยู่กับเวอร์ชันของ GLIBC >= 2.14 หากระบบปฏิบัติการของคุณเป็นระบบปฏิบัติการเก่าซึ่งมี GLIBC เวอร์ชันเปิดตัวก่อนปี 2011 ไลบรารีนี้จะไม่สามารถเรียกใช้ฟังก์ชันดั้งเดิมได้
หากต้องการแก้ไขปัญหานี้ ให้แยกพื้นที่เก็บข้อมูล และแทนที่แท็ก <version>
สำหรับสิ่งประดิษฐ์ jna
และ jna-platform
ในไฟล์ pom
ของโปรเจ็กต์
sudo apt-get ติดตั้ง libjna-java
sudo yum ติดตั้ง jna
ไลบรารีจะอ่าน /proc/cpuinfo
ของคุณหากคุณมีหรือจัดเตรียมไว้ให้ และจะกำหนดเค้าโครง CPU ของคุณ หากคุณไม่มีระบบจะถือว่า CPU ทุกตัวอยู่ในซ็อกเก็ต CPU เดียว
ไลบรารีจะค้นหา CPU ที่แยกออกมา ซึ่งพิจารณาจาก CPU ที่คุณไม่ได้ใช้งานตามค่าเริ่มต้น เช่น หากคุณมี CPU 16 ตัว แต่ 8 ตัวในนั้นไม่สามารถใช้งานได้ทั่วไป (ตามที่กำหนดโดยความสัมพันธ์ของกระบวนการเมื่อเริ่มต้นระบบ) ก็จะเริ่มกำหนดให้กับ CPU เหล่านั้น
หมายเหตุ: หากคุณมีมากกว่าหนึ่งกระบวนการที่ใช้ไลบรารีนี้ คุณต้องระบุว่า CPU ใดที่กระบวนการสามารถใช้ได้ ไม่เช่นนั้นกระบวนการจะกำหนด CPU เดียวกันให้กับทั้งสองกระบวนการ หากต้องการควบคุมว่ากระบวนการใดที่ CPU สามารถใช้ได้ ให้เพิ่ม -Daffinity.reserved={cpu-mask-in-hex} เข้ากับบรรทัดคำสั่งของกระบวนการ
หมายเหตุ: CPU 0 สงวนไว้สำหรับระบบปฏิบัติการ โดยจะต้องทำงานที่ไหนสักแห่ง
https://github.com/peter-lawrey/Java-Thread-Affinity/wiki/Getting-started
https://github.com/peter-lawrey/Java-Thread-Affinity/wiki/How-it-works
http://vanillajava.blogspot.co.uk/2013/07/micro-jitter-busy-waiting-and-binding.html
Java-Thread-Affinity ต้องการให้คุณแยก CPU บางตัวออกก่อน
เมื่อแกน CPU ถูกแยกออก ตัวกำหนดเวลา Linux จะไม่ใช้แกน CPU เพื่อรันกระบวนการพื้นที่ผู้ใช้ใดๆ CPU ที่แยกออกมาจะไม่มีส่วนร่วมในการปรับสมดุลโหลด และจะไม่มีงานทำงานบน CPU เหล่านั้น เว้นแต่จะได้รับมอบหมายอย่างชัดเจน
หากต้องการแยกแกน CPU ที่ 1 และ 3 (หมายเลข CPU เริ่มต้นที่ 0) บนระบบของคุณ ให้เพิ่มสิ่งต่อไปนี้ลงในบรรทัดคำสั่งเคอร์เนลระหว่างการบู๊ต:
ไอโซลปัส=1,3
คุณสามารถรับการล็อคสำหรับ CPU ได้ด้วยวิธีต่อไปนี้:
ในจาวา 6
AffinityLock al = AffinityLock . acquireLock ();
try {
// do some work locked to a CPU.
} finally {
al . release ();
}
ใน Java 7 หรือ 8
try ( AffinityLock al = AffinityLock . acquireLock ()) {
// do some work while locked to a CPU.
}
คุณมีตัวเลือกเพิ่มเติมเช่น
จองทั้งแกนก็ได้ หากคุณเปิดใช้งานไฮเปอร์เธรด การดำเนินการนี้จะใช้ CPU หนึ่งตัว และปล่อยให้เป็น CPU คู่ที่ไม่ได้ใช้
try ( AffinityLock al = AffinityLock . acquireCore ()) {
// do some work while locked to a CPU.
}
คุณสามารถเลือกเค้าโครงที่สัมพันธ์กับการล็อคที่มีอยู่ได้
try ( final AffinityLock al = AffinityLock . acquireLock ()) {
System . out . println ( "Main locked" );
Thread t = new Thread ( new Runnable () {
@ Override
public void run () {
try ( AffinityLock al2 = al . acquireLock ( AffinityStrategies . SAME_SOCKET ,
AffinityStrategies . ANY )) {
System . out . println ( "Thread-0 locked" );
}
}
});
t . start ();
}
ในตัวอย่างนี้ ไลบรารีจะเลือกใช้ CPU ที่ว่างบนซ็อกเก็ตเดียวกันกับเธรดแรก ไม่เช่นนั้นไลบรารีจะเลือก CPU ที่ว่างใดๆ
คุณสามารถรับรหัสเธรดปัจจุบันได้โดยใช้
int threadId = AffinitySupport . getThreadId ();
คุณสามารถรับ CPU ปัจจุบันที่กำลังใช้งานอยู่ได้
int cpuId = AffinitySupport . getCpu ();
ความเกี่ยวข้องของกระบวนการเมื่อเริ่มต้นระบบคือ
long baseAffinity = AffinityLock . BASE_AFFINITY ;
CPU ที่จองได้คือ
long reservedAffinity = AffinityLock . RESERVED_AFFINITY ;
หากคุณต้องการรับ/ตั้งค่าความสัมพันธ์โดยตรง คุณสามารถทำได้
long currentAffinity = AffinitySupport . getAffinity ();
AffinitySupport . setAffinity ( 1L << 5 ); // lock to CPU 5.
สำหรับรายละเอียดมุมมองของสถานะความสัมพันธ์ปัจจุบัน (ตามที่เห็นในไลบรารี) ให้รันสคริปต์ต่อไปนี้บนระบบ Linux:
# change to the affinity lock-file directory (defaults to system property java.io.tmpdir)
$ cd /tmp
# dump affinity state
$ for i in "$(ls cpu-*)";
do PID="$(cat $i | head -n1)"; TIMESTAMP="$(cat $i | tail -n1)";
echo "pid $PID locked at $TIMESTAMP in $i"; taskset -cp $PID;
cat "/proc/$PID/cmdline"; echo; echo
done
pid 14584 locked at 2017.10.30 at 10:33:24 GMT in cpu-3.lock
pid 14584's current affinity list: 3
/opt/jdk1.8.0_141/bin/java ...
กลุ่มสนับสนุน Java Thread Affinity
สำหรับบทความเกี่ยวกับความสัมพันธ์ที่สามารถสร้างความแตกต่างได้มากเพียงใดและวิธีใช้งานhttp://vanillajava.blogspot.com/2013/07/micro-jitter-busy-waiting-and-binding.html
ขณะนี้ฉันกำลังทำงานในโปรเจ็กต์ที่เกี่ยวข้องกับการตรวจจับการหยุดชะงักในโปรแกรมแบบมัลติเธรดใน java เรากำลังพยายามเรียกใช้เธรดบนโปรเซสเซอร์ที่แตกต่างกัน และพบโพสต์ GitHub ของคุณเกี่ยวกับเรื่องเดียวกัน https://github.com/peter-lawrey/Java-Thread-Affinity/wiki/Getting-started เนื่องจากเป็นมือใหม่ ฉันมีความรู้น้อยจึงต้องการความช่วยเหลือจากคุณ เราจำเป็นต้องรู้วิธีรันเธรดตามหมายเลข cpu ที่ระบุ จากนั้นจึงสลับเธรดเมื่อมีใครรออยู่
// lock a cpuId
try ( AffinityLock lock = AffinityLock . acquireLock ( n )) {
}
โดยที่ n คือ cpu ที่คุณต้องการรันเธรด
หรือ
// lock one of the last CPUs
try ( AffinityLock lock = AffinityLock . acquireLockLastMinus ( n )) {
}
ฉันมี cpuId ในไฟล์กำหนดค่า ฉันจะตั้งค่าโดยใช้สตริงได้อย่างไร
try ( AffinityLock lock = AffinityLock . acquireLock ( "last" )) {
assertEquals ( PROCESSORS - 1 , Affinity . getCpu ());
}
try ( AffinityLock lock = AffinityLock . acquireLock ( "last-1" )) {
assertEquals ( PROCESSORS - 2 , Affinity . getCpu ());
}
try ( AffinityLock lock = AffinityLock . acquireLock ( "1" )) {
assertEquals ( 1 , Affinity . getCpu ());
}
try ( AffinityLock lock = AffinityLock . acquireLock ( "any" )) {
assertTrue ( lock . bound );
}
try ( AffinityLock lock = AffinityLock . acquireLock ( "none" )) {
assertFalse ( lock . bound );
}
try ( AffinityLock lock = AffinityLock . acquireLock (( String ) null )) {
assertFalse ( lock . bound );
}
try ( AffinityLock lock = AffinityLock . acquireLock ( "0" )) { // prints a warning
assertFalse ( lock . bound );
}