.NET: ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್ ಮತ್ತು ಅಸಿಂಕ್ರೊನಿಯೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವ ಪರಿಕರಗಳು. ಭಾಗ 1

ನಾನು Habr ನಲ್ಲಿ ಮೂಲ ಲೇಖನವನ್ನು ಪ್ರಕಟಿಸುತ್ತಿದ್ದೇನೆ, ಅದರ ಅನುವಾದವನ್ನು ಕಾರ್ಪೊರೇಟ್‌ನಲ್ಲಿ ಪೋಸ್ಟ್ ಮಾಡಲಾಗಿದೆ ಬ್ಲಾಗ್ ಪೋಸ್ಟ್.

ಇಲ್ಲಿ ಮತ್ತು ಈಗ ಫಲಿತಾಂಶಕ್ಕಾಗಿ ಕಾಯದೆ, ಅಸಮಕಾಲಿಕವಾಗಿ ಏನನ್ನಾದರೂ ಮಾಡುವ ಅಗತ್ಯತೆ ಅಥವಾ ಅದನ್ನು ನಿರ್ವಹಿಸುವ ಹಲವಾರು ಘಟಕಗಳ ನಡುವೆ ದೊಡ್ಡ ಕೆಲಸವನ್ನು ವಿಭಜಿಸುವುದು ಕಂಪ್ಯೂಟರ್ಗಳ ಆಗಮನದ ಮೊದಲು ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ. ಅವರ ಆಗಮನದೊಂದಿಗೆ, ಈ ಅಗತ್ಯವು ಬಹಳ ಸ್ಪಷ್ಟವಾಯಿತು. ಈಗ, 2019 ರಲ್ಲಿ, ನಾನು ಈ ಲೇಖನವನ್ನು 8-ಕೋರ್ ಇಂಟೆಲ್ ಕೋರ್ ಪ್ರೊಸೆಸರ್ ಹೊಂದಿರುವ ಲ್ಯಾಪ್‌ಟಾಪ್‌ನಲ್ಲಿ ಟೈಪ್ ಮಾಡುತ್ತಿದ್ದೇನೆ, ಇದರಲ್ಲಿ ನೂರಕ್ಕೂ ಹೆಚ್ಚು ಪ್ರಕ್ರಿಯೆಗಳು ಸಮಾನಾಂತರವಾಗಿ ಚಾಲನೆಯಲ್ಲಿವೆ ಮತ್ತು ಇನ್ನೂ ಹೆಚ್ಚಿನ ಥ್ರೆಡ್‌ಗಳು. ಹತ್ತಿರದಲ್ಲಿ, ಸ್ವಲ್ಪ ಕಳಪೆ ಫೋನ್ ಇದೆ, ಒಂದೆರಡು ವರ್ಷಗಳ ಹಿಂದೆ ಖರೀದಿಸಲಾಗಿದೆ, ಇದು ಬೋರ್ಡ್‌ನಲ್ಲಿ 8-ಕೋರ್ ಪ್ರೊಸೆಸರ್ ಅನ್ನು ಹೊಂದಿದೆ. ವಿಷಯಾಧಾರಿತ ಸಂಪನ್ಮೂಲಗಳು ಲೇಖನಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳಿಂದ ತುಂಬಿವೆ, ಅಲ್ಲಿ ಅವರ ಲೇಖಕರು 16-ಕೋರ್ ಪ್ರೊಸೆಸರ್‌ಗಳನ್ನು ಒಳಗೊಂಡಿರುವ ಈ ವರ್ಷದ ಪ್ರಮುಖ ಸ್ಮಾರ್ಟ್‌ಫೋನ್‌ಗಳನ್ನು ಮೆಚ್ಚುತ್ತಾರೆ. MS Azure ಒಂದು ವರ್ಚುವಲ್ ಯಂತ್ರವನ್ನು 20 ಕೋರ್ ಪ್ರೊಸೆಸರ್ ಮತ್ತು 128 TB RAM ಅನ್ನು $2/ಗಂಟೆಗಿಂತ ಕಡಿಮೆಗೆ ಒದಗಿಸುತ್ತದೆ. ದುರದೃಷ್ಟವಶಾತ್, ಗರಿಷ್ಠವನ್ನು ಹೊರತೆಗೆಯಲು ಮತ್ತು ಎಳೆಗಳ ಪರಸ್ಪರ ಕ್ರಿಯೆಯನ್ನು ನಿರ್ವಹಿಸಲು ಸಾಧ್ಯವಾಗದೆ ಈ ಶಕ್ತಿಯನ್ನು ಬಳಸಿಕೊಳ್ಳುವುದು ಅಸಾಧ್ಯ.

ಪರಿಭಾಷೆ

ಪ್ರಕ್ರಿಯೆ - OS ಆಬ್ಜೆಕ್ಟ್, ಪ್ರತ್ಯೇಕವಾದ ವಿಳಾಸ ಸ್ಥಳ, ಎಳೆಗಳನ್ನು ಒಳಗೊಂಡಿದೆ.
ಎಳೆ - ಓಎಸ್ ಆಬ್ಜೆಕ್ಟ್, ಎಕ್ಸಿಕ್ಯೂಶನ್‌ನ ಚಿಕ್ಕ ಘಟಕ, ಪ್ರಕ್ರಿಯೆಯ ಭಾಗ, ಥ್ರೆಡ್‌ಗಳು ಪ್ರಕ್ರಿಯೆಯೊಳಗೆ ಮೆಮೊರಿ ಮತ್ತು ಇತರ ಸಂಪನ್ಮೂಲಗಳನ್ನು ತಮ್ಮಲ್ಲಿ ಹಂಚಿಕೊಳ್ಳುತ್ತವೆ.
ಬಹುಕಾರ್ಯಕ - OS ಆಸ್ತಿ, ಹಲವಾರು ಪ್ರಕ್ರಿಯೆಗಳನ್ನು ಏಕಕಾಲದಲ್ಲಿ ಚಲಾಯಿಸುವ ಸಾಮರ್ಥ್ಯ
ಮಲ್ಟಿ-ಕೋರ್ - ಪ್ರೊಸೆಸರ್‌ನ ಆಸ್ತಿ, ಡೇಟಾ ಸಂಸ್ಕರಣೆಗಾಗಿ ಹಲವಾರು ಕೋರ್‌ಗಳನ್ನು ಬಳಸುವ ಸಾಮರ್ಥ್ಯ
ಮಲ್ಟಿಪ್ರೊಸೆಸಿಂಗ್ - ಕಂಪ್ಯೂಟರ್‌ನ ಆಸ್ತಿ, ಭೌತಿಕವಾಗಿ ಹಲವಾರು ಪ್ರೊಸೆಸರ್‌ಗಳೊಂದಿಗೆ ಏಕಕಾಲದಲ್ಲಿ ಕೆಲಸ ಮಾಡುವ ಸಾಮರ್ಥ್ಯ
ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್ - ಪ್ರಕ್ರಿಯೆಯ ಆಸ್ತಿ, ಹಲವಾರು ಎಳೆಗಳ ನಡುವೆ ಡೇಟಾ ಸಂಸ್ಕರಣೆಯನ್ನು ವಿತರಿಸುವ ಸಾಮರ್ಥ್ಯ.
ಸಮಾನಾಂತರತೆ - ಸಮಯದ ಪ್ರತಿ ಘಟಕಕ್ಕೆ ಏಕಕಾಲದಲ್ಲಿ ಹಲವಾರು ಕ್ರಿಯೆಗಳನ್ನು ಭೌತಿಕವಾಗಿ ನಿರ್ವಹಿಸುವುದು
ಅಸಿಂಕ್ರೊನಿ - ಈ ಪ್ರಕ್ರಿಯೆಯ ಪೂರ್ಣಗೊಳ್ಳುವವರೆಗೆ ಕಾಯದೆ ಕಾರ್ಯಾಚರಣೆಯ ಮರಣದಂಡನೆ; ಮರಣದಂಡನೆಯ ಫಲಿತಾಂಶವನ್ನು ನಂತರ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಬಹುದು.

ರೂಪಕ

ಎಲ್ಲಾ ವ್ಯಾಖ್ಯಾನಗಳು ಉತ್ತಮವಾಗಿಲ್ಲ ಮತ್ತು ಕೆಲವು ಹೆಚ್ಚುವರಿ ವಿವರಣೆಯ ಅಗತ್ಯವಿರುತ್ತದೆ, ಆದ್ದರಿಂದ ನಾನು ಔಪಚಾರಿಕವಾಗಿ ಪರಿಚಯಿಸಲಾದ ಪರಿಭಾಷೆಗೆ ಉಪಹಾರವನ್ನು ಅಡುಗೆ ಮಾಡುವ ಬಗ್ಗೆ ರೂಪಕವನ್ನು ಸೇರಿಸುತ್ತೇನೆ. ಈ ರೂಪಕದಲ್ಲಿ ಉಪಹಾರವನ್ನು ಬೇಯಿಸುವುದು ಒಂದು ಪ್ರಕ್ರಿಯೆ.

ಬೆಳಿಗ್ಗೆ ಉಪಾಹಾರವನ್ನು ತಯಾರಿಸುವಾಗ ನಾನು (ಸಿಪಿಯುನಾನು ಅಡುಗೆ ಮನೆಗೆ ಬರುತ್ತೇನೆ (ಕಂಪ್ಯೂಟರ್) ನನಗೆ 2 ಕೈಗಳಿವೆ (ಕೋರ್ಗಳು) ಅಡುಗೆಮನೆಯಲ್ಲಿ ಹಲವಾರು ಸಾಧನಗಳಿವೆ (IO): ಓವನ್, ಕೆಟಲ್, ಟೋಸ್ಟರ್, ರೆಫ್ರಿಜರೇಟರ್. ನಾನು ಅನಿಲವನ್ನು ಆನ್ ಮಾಡಿ, ಅದರ ಮೇಲೆ ಹುರಿಯಲು ಪ್ಯಾನ್ ಹಾಕಿ ಮತ್ತು ಅದು ಬಿಸಿಯಾಗಲು ಕಾಯದೆ ಎಣ್ಣೆಯನ್ನು ಸುರಿಯಿರಿ (ಅಸಮಕಾಲಿಕವಾಗಿ, ನಾನ್-ಬ್ಲಾಕಿಂಗ್-ಐಒ-ವೇಟ್), ನಾನು ರೆಫ್ರಿಜರೇಟರ್‌ನಿಂದ ಮೊಟ್ಟೆಗಳನ್ನು ತೆಗೆದುಕೊಂಡು ಅವುಗಳನ್ನು ಪ್ಲೇಟ್‌ಗೆ ಒಡೆಯುತ್ತೇನೆ, ನಂತರ ಅವುಗಳನ್ನು ಒಂದು ಕೈಯಿಂದ ಸೋಲಿಸುತ್ತೇನೆ (ಥ್ರೆಡ್ # 1), ಮತ್ತು ಎರಡನೇ (ಥ್ರೆಡ್ # 2) ಪ್ಲೇಟ್ ಅನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುವುದು (ಹಂಚಿಕೊಂಡ ಸಂಪನ್ಮೂಲ). ಈಗ ನಾನು ಕೆಟಲ್ ಅನ್ನು ಆನ್ ಮಾಡಲು ಬಯಸುತ್ತೇನೆ, ಆದರೆ ನನಗೆ ಸಾಕಷ್ಟು ಕೈಗಳಿಲ್ಲ (ಥ್ರೆಡ್ ಹಸಿವು) ಈ ಸಮಯದಲ್ಲಿ, ಹುರಿಯಲು ಪ್ಯಾನ್ ಬಿಸಿಯಾಗುತ್ತದೆ (ಫಲಿತಾಂಶವನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವುದು) ಅದರಲ್ಲಿ ನಾನು ಚಾವಟಿ ಮಾಡಿದ್ದನ್ನು ಸುರಿಯುತ್ತೇನೆ. ನಾನು ಕೆಟಲ್ ಅನ್ನು ತಲುಪುತ್ತೇನೆ ಮತ್ತು ಅದನ್ನು ಆನ್ ಮಾಡಿ ಮತ್ತು ಅದರಲ್ಲಿ ನೀರು ಕುದಿಯುವುದನ್ನು ಮೂರ್ಖತನದಿಂದ ನೋಡುತ್ತೇನೆ (ನಿರ್ಬಂಧಿಸುವುದು-ಐಒ-ವೇಟ್), ಈ ಸಮಯದಲ್ಲಿ ಅವರು ಆಮ್ಲೆಟ್ ಅನ್ನು ಚಾವಟಿ ಮಾಡಿದ ಪ್ಲೇಟ್ ಅನ್ನು ತೊಳೆಯಬಹುದಿತ್ತು.

ನಾನು ಕೇವಲ 2 ಕೈಗಳನ್ನು ಬಳಸಿ ಆಮ್ಲೆಟ್ ಅನ್ನು ಬೇಯಿಸಿದ್ದೇನೆ ಮತ್ತು ನನ್ನ ಬಳಿ ಹೆಚ್ಚಿಲ್ಲ, ಆದರೆ ಅದೇ ಸಮಯದಲ್ಲಿ, ಆಮ್ಲೆಟ್ ಅನ್ನು ಬೀಸುವ ಕ್ಷಣದಲ್ಲಿ, 3 ಕಾರ್ಯಾಚರಣೆಗಳು ಏಕಕಾಲದಲ್ಲಿ ನಡೆದವು: ಆಮ್ಲೆಟ್ ಅನ್ನು ಬೀಸುವುದು, ತಟ್ಟೆಯನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುವುದು, ಬಾಣಲೆಯನ್ನು ಬಿಸಿ ಮಾಡುವುದು. CPU ಕಂಪ್ಯೂಟರ್‌ನ ಅತ್ಯಂತ ವೇಗದ ಭಾಗವಾಗಿದೆ, IO ಎಂದರೆ ಎಲ್ಲವೂ ನಿಧಾನವಾಗುತ್ತದೆ, ಆದ್ದರಿಂದ IO ನಿಂದ ಡೇಟಾವನ್ನು ಸ್ವೀಕರಿಸುವಾಗ CPU ಅನ್ನು ಯಾವುದನ್ನಾದರೂ ಆಕ್ರಮಿಸಿಕೊಳ್ಳುವುದು ಪರಿಣಾಮಕಾರಿ ಪರಿಹಾರವಾಗಿದೆ.

ರೂಪಕವನ್ನು ಮುಂದುವರಿಸುವುದು:

  • ಆಮ್ಲೆಟ್ ತಯಾರಿಸುವ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿ, ನಾನು ಬಟ್ಟೆಗಳನ್ನು ಬದಲಾಯಿಸಲು ಪ್ರಯತ್ನಿಸಿದರೆ, ಇದು ಬಹುಕಾರ್ಯಕಕ್ಕೆ ಉದಾಹರಣೆಯಾಗಿದೆ. ಒಂದು ಪ್ರಮುಖ ಸೂಕ್ಷ್ಮ ವ್ಯತ್ಯಾಸ: ಕಂಪ್ಯೂಟರ್‌ಗಳು ಜನರಿಗಿಂತ ಹೆಚ್ಚು ಉತ್ತಮವಾಗಿವೆ.
  • ಹಲವಾರು ಬಾಣಸಿಗರನ್ನು ಹೊಂದಿರುವ ಅಡಿಗೆ, ಉದಾಹರಣೆಗೆ ರೆಸ್ಟೋರೆಂಟ್‌ನಲ್ಲಿ - ಮಲ್ಟಿ-ಕೋರ್ ಕಂಪ್ಯೂಟರ್.
  • ಶಾಪಿಂಗ್ ಕೇಂದ್ರದಲ್ಲಿ ಆಹಾರ ನ್ಯಾಯಾಲಯದಲ್ಲಿ ಅನೇಕ ರೆಸ್ಟೋರೆಂಟ್‌ಗಳು - ಡೇಟಾ ಸೆಂಟರ್

.NET ಪರಿಕರಗಳು

.NET ಅನೇಕ ಇತರ ವಿಷಯಗಳಂತೆ ಥ್ರೆಡ್‌ಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು ಉತ್ತಮವಾಗಿದೆ. ಪ್ರತಿ ಹೊಸ ಆವೃತ್ತಿಯೊಂದಿಗೆ, ಇದು ಅವರೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು ಹೆಚ್ಚು ಹೆಚ್ಚು ಹೊಸ ಪರಿಕರಗಳನ್ನು ಪರಿಚಯಿಸುತ್ತದೆ, OS ಥ್ರೆಡ್‌ಗಳ ಮೇಲೆ ಅಮೂರ್ತತೆಯ ಹೊಸ ಪದರಗಳು. ಅಮೂರ್ತತೆಗಳ ನಿರ್ಮಾಣದೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವಾಗ, ಫ್ರೇಮ್‌ವರ್ಕ್ ಡೆವಲಪರ್‌ಗಳು ಉನ್ನತ ಮಟ್ಟದ ಅಮೂರ್ತತೆಯನ್ನು ಬಳಸುವಾಗ, ಒಂದು ಅಥವಾ ಹೆಚ್ಚಿನ ಹಂತಗಳನ್ನು ಕೆಳಗೆ ಹೋಗಲು ಅವಕಾಶವನ್ನು ಬಿಡುವ ವಿಧಾನವನ್ನು ಬಳಸುತ್ತಾರೆ. ಹೆಚ್ಚಾಗಿ ಇದು ಅನಿವಾರ್ಯವಲ್ಲ, ವಾಸ್ತವವಾಗಿ ಇದು ಶಾಟ್‌ಗನ್‌ನಿಂದ ನಿಮ್ಮನ್ನು ಪಾದದಲ್ಲಿ ಶೂಟ್ ಮಾಡಲು ಬಾಗಿಲು ತೆರೆಯುತ್ತದೆ, ಆದರೆ ಕೆಲವೊಮ್ಮೆ, ಅಪರೂಪದ ಸಂದರ್ಭಗಳಲ್ಲಿ, ಪ್ರಸ್ತುತ ಅಮೂರ್ತತೆಯ ಮಟ್ಟದಲ್ಲಿ ಪರಿಹರಿಸಲಾಗದ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸಲು ಇದು ಏಕೈಕ ಮಾರ್ಗವಾಗಿದೆ. .

ಪರಿಕರಗಳ ಮೂಲಕ, ನನ್ನ ಪ್ರಕಾರ ಫ್ರೇಮ್‌ವರ್ಕ್ ಮತ್ತು ಥರ್ಡ್-ಪಾರ್ಟಿ ಪ್ಯಾಕೇಜುಗಳಿಂದ ಒದಗಿಸಲಾದ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರೋಗ್ರಾಮಿಂಗ್ ಇಂಟರ್‌ಫೇಸ್‌ಗಳು (API ಗಳು), ಹಾಗೆಯೇ ಮಲ್ಟಿ-ಥ್ರೆಡ್ ಕೋಡ್‌ಗೆ ಸಂಬಂಧಿಸಿದ ಯಾವುದೇ ಸಮಸ್ಯೆಗಳ ಹುಡುಕಾಟವನ್ನು ಸರಳಗೊಳಿಸುವ ಸಂಪೂರ್ಣ ಸಾಫ್ಟ್‌ವೇರ್ ಪರಿಹಾರಗಳು.

ಥ್ರೆಡ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ

ಥ್ರೆಡ್ ವರ್ಗವು ಥ್ರೆಡ್ಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು .NET ನಲ್ಲಿ ಅತ್ಯಂತ ಮೂಲಭೂತ ವರ್ಗವಾಗಿದೆ. ಕನ್ಸ್ಟ್ರಕ್ಟರ್ ಎರಡು ಪ್ರತಿನಿಧಿಗಳಲ್ಲಿ ಒಂದನ್ನು ಸ್ವೀಕರಿಸುತ್ತಾರೆ:

  • ಥ್ರೆಡ್‌ಸ್ಟಾರ್ಟ್ - ಯಾವುದೇ ನಿಯತಾಂಕಗಳಿಲ್ಲ
  • ParametrizedThreadStart - ಪ್ರಕಾರದ ವಸ್ತುವಿನ ಒಂದು ನಿಯತಾಂಕದೊಂದಿಗೆ.

ಪ್ರಾರಂಭ ವಿಧಾನವನ್ನು ಕರೆದ ನಂತರ ಹೊಸದಾಗಿ ರಚಿಸಲಾದ ಥ್ರೆಡ್‌ನಲ್ಲಿ ಪ್ರತಿನಿಧಿಯನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗುತ್ತದೆ. ಪ್ಯಾರಾಮೆಟ್ರಿಸ್ಡ್ ಥ್ರೆಡ್‌ಸ್ಟಾರ್ಟ್ ಪ್ರಕಾರದ ಪ್ರತಿನಿಧಿಯನ್ನು ಕನ್‌ಸ್ಟ್ರಕ್ಟರ್‌ಗೆ ರವಾನಿಸಿದ್ದರೆ, ನಂತರ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ಪ್ರಾರಂಭ ವಿಧಾನಕ್ಕೆ ರವಾನಿಸಬೇಕು. ಯಾವುದೇ ಸ್ಥಳೀಯ ಮಾಹಿತಿಯನ್ನು ಸ್ಟ್ರೀಮ್‌ಗೆ ವರ್ಗಾಯಿಸಲು ಈ ಕಾರ್ಯವಿಧಾನದ ಅಗತ್ಯವಿದೆ. ಥ್ರೆಡ್ ಅನ್ನು ರಚಿಸುವುದು ದುಬಾರಿ ಕಾರ್ಯಾಚರಣೆಯಾಗಿದೆ ಎಂದು ಗಮನಿಸಬೇಕಾದ ಅಂಶವಾಗಿದೆ, ಮತ್ತು ಥ್ರೆಡ್ ಸ್ವತಃ ಭಾರವಾದ ವಸ್ತುವಾಗಿದೆ, ಏಕೆಂದರೆ ಇದು ಸ್ಟಾಕ್ನಲ್ಲಿ 1MB ಮೆಮೊರಿಯನ್ನು ನಿಯೋಜಿಸುತ್ತದೆ ಮತ್ತು OS API ನೊಂದಿಗೆ ಪರಸ್ಪರ ಕ್ರಿಯೆಯ ಅಗತ್ಯವಿರುತ್ತದೆ.

new Thread(...).Start(...);

ಥ್ರೆಡ್‌ಪೂಲ್ ವರ್ಗವು ಪೂಲ್‌ನ ಪರಿಕಲ್ಪನೆಯನ್ನು ಪ್ರತಿನಿಧಿಸುತ್ತದೆ. .NET ನಲ್ಲಿ, ಥ್ರೆಡ್ ಪೂಲ್ ಎಂಜಿನಿಯರಿಂಗ್‌ನ ಒಂದು ಭಾಗವಾಗಿದೆ ಮತ್ತು ಮೈಕ್ರೋಸಾಫ್ಟ್‌ನಲ್ಲಿನ ಡೆವಲಪರ್‌ಗಳು ಇದು ವಿವಿಧ ರೀತಿಯ ಸನ್ನಿವೇಶಗಳಲ್ಲಿ ಅತ್ಯುತ್ತಮವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು ಸಾಕಷ್ಟು ಪ್ರಯತ್ನಗಳನ್ನು ಮಾಡಿದ್ದಾರೆ.

ಸಾಮಾನ್ಯ ಪರಿಕಲ್ಪನೆ:

ಅಪ್ಲಿಕೇಶನ್ ಪ್ರಾರಂಭವಾದ ಕ್ಷಣದಿಂದ, ಇದು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಮೀಸಲು ಹಲವಾರು ಎಳೆಗಳನ್ನು ರಚಿಸುತ್ತದೆ ಮತ್ತು ಅವುಗಳನ್ನು ಬಳಕೆಗೆ ತೆಗೆದುಕೊಳ್ಳುವ ಸಾಮರ್ಥ್ಯವನ್ನು ಒದಗಿಸುತ್ತದೆ. ಥ್ರೆಡ್‌ಗಳನ್ನು ಆಗಾಗ್ಗೆ ಮತ್ತು ಹೆಚ್ಚಿನ ಸಂಖ್ಯೆಯಲ್ಲಿ ಬಳಸಿದರೆ, ಕಾಲರ್‌ನ ಅಗತ್ಯಗಳನ್ನು ಪೂರೈಸಲು ಪೂಲ್ ವಿಸ್ತರಿಸುತ್ತದೆ. ಸರಿಯಾದ ಸಮಯದಲ್ಲಿ ಪೂಲ್‌ನಲ್ಲಿ ಯಾವುದೇ ಉಚಿತ ಥ್ರೆಡ್‌ಗಳಿಲ್ಲದಿದ್ದಾಗ, ಅದು ಥ್ರೆಡ್‌ಗಳಲ್ಲಿ ಒಂದನ್ನು ಹಿಂತಿರುಗಿಸಲು ಕಾಯುತ್ತದೆ ಅಥವಾ ಹೊಸದನ್ನು ರಚಿಸುತ್ತದೆ. ಥ್ರೆಡ್ ಪೂಲ್ ಕೆಲವು ಅಲ್ಪಾವಧಿಯ ಕ್ರಿಯೆಗಳಿಗೆ ಉತ್ತಮವಾಗಿದೆ ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌ನ ಸಂಪೂರ್ಣ ಕಾರ್ಯಾಚರಣೆಯ ಉದ್ದಕ್ಕೂ ಸೇವೆಗಳಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುವ ಕಾರ್ಯಾಚರಣೆಗಳಿಗೆ ಸರಿಯಾಗಿ ಸೂಕ್ತವಲ್ಲ ಎಂದು ಅದು ಅನುಸರಿಸುತ್ತದೆ.

ಪೂಲ್‌ನಿಂದ ಥ್ರೆಡ್ ಅನ್ನು ಬಳಸಲು, WaitCallback ಪ್ರಕಾರದ ಪ್ರತಿನಿಧಿಯನ್ನು ಸ್ವೀಕರಿಸುವ QueueUserWorkItem ವಿಧಾನವಿದೆ, ಇದು ParametrizedThreadStart ನಂತೆಯೇ ಅದೇ ಸಹಿಯನ್ನು ಹೊಂದಿದೆ ಮತ್ತು ಅದಕ್ಕೆ ರವಾನಿಸಲಾದ ಪ್ಯಾರಾಮೀಟರ್ ಅದೇ ಕಾರ್ಯವನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ.

ThreadPool.QueueUserWorkItem(...);

ಕಡಿಮೆ-ತಿಳಿದಿರುವ ಥ್ರೆಡ್ ಪೂಲ್ ವಿಧಾನವನ್ನು RegisterWaitForSingleObject ಅನ್ನು ನಿರ್ಬಂಧಿಸದ IO ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಸಂಘಟಿಸಲು ಬಳಸಲಾಗುತ್ತದೆ. ಈ ವಿಧಾನಕ್ಕೆ ರವಾನಿಸಲಾದ ಪ್ರತಿನಿಧಿಯನ್ನು WaitHandle ವಿಧಾನಕ್ಕೆ ರವಾನಿಸಿದಾಗ "ಬಿಡುಗಡೆಯಾಗಿದೆ" ಎಂದು ಕರೆಯಲಾಗುವುದು.

ThreadPool.RegisterWaitForSingleObject(...)

.NET ಥ್ರೆಡ್ ಟೈಮರ್ ಅನ್ನು ಹೊಂದಿದೆ ಮತ್ತು ಇದು WinForms/WPF ಟೈಮರ್‌ಗಳಿಂದ ಭಿನ್ನವಾಗಿದೆ, ಅದರ ಹ್ಯಾಂಡ್ಲರ್ ಅನ್ನು ಪೂಲ್‌ನಿಂದ ತೆಗೆದ ಥ್ರೆಡ್‌ನಲ್ಲಿ ಕರೆಯಲಾಗುವುದು.

System.Threading.Timer

ಪೂಲ್‌ನಿಂದ ಥ್ರೆಡ್‌ಗೆ ಮರಣದಂಡನೆಗಾಗಿ ಪ್ರತಿನಿಧಿಯನ್ನು ಕಳುಹಿಸಲು ಸಾಕಷ್ಟು ವಿಲಕ್ಷಣ ಮಾರ್ಗವಿದೆ - ಬಿಗಿನ್‌ವೋಕ್ ವಿಧಾನ.

DelegateInstance.BeginInvoke

ಮೇಲಿನ ಹಲವು ವಿಧಾನಗಳನ್ನು ಕರೆಯಬಹುದಾದ ಕಾರ್ಯದ ಕುರಿತು ನಾನು ಸಂಕ್ಷಿಪ್ತವಾಗಿ ವಾಸಿಸಲು ಬಯಸುತ್ತೇನೆ - Kernel32.dll Win32 API ನಿಂದ CreateThread. ಈ ಕಾರ್ಯವನ್ನು ಕರೆಯಲು ಬಾಹ್ಯ ವಿಧಾನಗಳ ಕಾರ್ಯವಿಧಾನಕ್ಕೆ ಧನ್ಯವಾದಗಳು, ಒಂದು ಮಾರ್ಗವಿದೆ. ಲೆಗಸಿ ಕೋಡ್‌ನ ಭಯಾನಕ ಉದಾಹರಣೆಯಲ್ಲಿ ನಾನು ಅಂತಹ ಕರೆಯನ್ನು ಒಮ್ಮೆ ಮಾತ್ರ ನೋಡಿದ್ದೇನೆ ಮತ್ತು ನಿಖರವಾಗಿ ಇದನ್ನು ಮಾಡಿದ ಲೇಖಕರ ಪ್ರೇರಣೆ ನನಗೆ ಇನ್ನೂ ರಹಸ್ಯವಾಗಿ ಉಳಿದಿದೆ.

Kernel32.dll CreateThread

ಥ್ರೆಡ್‌ಗಳನ್ನು ನೋಡುವುದು ಮತ್ತು ಡೀಬಗ್ ಮಾಡುವುದು

ನೀವು ರಚಿಸಿದ ಥ್ರೆಡ್‌ಗಳು, ಎಲ್ಲಾ ಮೂರನೇ ವ್ಯಕ್ತಿಯ ಘಟಕಗಳು ಮತ್ತು .NET ಪೂಲ್ ಅನ್ನು ವಿಷುಯಲ್ ಸ್ಟುಡಿಯೊದ ಥ್ರೆಡ್‌ಗಳ ವಿಂಡೋದಲ್ಲಿ ವೀಕ್ಷಿಸಬಹುದು. ಅಪ್ಲಿಕೇಶನ್ ಡೀಬಗ್ ಅಡಿಯಲ್ಲಿ ಮತ್ತು ಬ್ರೇಕ್ ಮೋಡ್‌ನಲ್ಲಿರುವಾಗ ಮಾತ್ರ ಈ ವಿಂಡೋ ಥ್ರೆಡ್ ಮಾಹಿತಿಯನ್ನು ಪ್ರದರ್ಶಿಸುತ್ತದೆ. ಇಲ್ಲಿ ನೀವು ಪ್ರತಿ ಥ್ರೆಡ್‌ನ ಸ್ಟಾಕ್ ಹೆಸರುಗಳು ಮತ್ತು ಆದ್ಯತೆಗಳನ್ನು ಅನುಕೂಲಕರವಾಗಿ ವೀಕ್ಷಿಸಬಹುದು ಮತ್ತು ನಿರ್ದಿಷ್ಟ ಥ್ರೆಡ್‌ಗೆ ಡೀಬಗ್ ಮಾಡುವುದನ್ನು ಬದಲಾಯಿಸಬಹುದು. ಥ್ರೆಡ್ ವರ್ಗದ ಆದ್ಯತೆಯ ಆಸ್ತಿಯನ್ನು ಬಳಸಿಕೊಂಡು, ನೀವು ಥ್ರೆಡ್‌ನ ಆದ್ಯತೆಯನ್ನು ಹೊಂದಿಸಬಹುದು, ಥ್ರೆಡ್‌ಗಳ ನಡುವೆ ಪ್ರೊಸೆಸರ್ ಸಮಯವನ್ನು ವಿಭಜಿಸುವಾಗ OC ಮತ್ತು CLR ಶಿಫಾರಸಿನಂತೆ ಗ್ರಹಿಸುತ್ತದೆ.

.NET: ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್ ಮತ್ತು ಅಸಿಂಕ್ರೊನಿಯೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವ ಪರಿಕರಗಳು. ಭಾಗ 1

ಟಾಸ್ಕ್ ಪ್ಯಾರಲಲ್ ಲೈಬ್ರರಿ

ಟಾಸ್ಕ್ ಪ್ಯಾರಲಲ್ ಲೈಬ್ರರಿ (TPL) ಅನ್ನು .NET 4.0 ನಲ್ಲಿ ಪರಿಚಯಿಸಲಾಯಿತು. ಈಗ ಇದು ಅಸಿಂಕ್ರೊನಿಯೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು ಪ್ರಮಾಣಿತ ಮತ್ತು ಮುಖ್ಯ ಸಾಧನವಾಗಿದೆ. ಹಳೆಯ ವಿಧಾನವನ್ನು ಬಳಸುವ ಯಾವುದೇ ಕೋಡ್ ಅನ್ನು ಪರಂಪರೆ ಎಂದು ಪರಿಗಣಿಸಲಾಗುತ್ತದೆ. TPL ನ ಮೂಲ ಘಟಕವು System.Threading.Tasks ನೇಮ್‌ಸ್ಪೇಸ್‌ನಿಂದ ಟಾಸ್ಕ್ ವರ್ಗವಾಗಿದೆ. ಕಾರ್ಯವು ಥ್ರೆಡ್‌ನ ಮೇಲಿನ ಅಮೂರ್ತತೆಯಾಗಿದೆ. C# ಭಾಷೆಯ ಹೊಸ ಆವೃತ್ತಿಯೊಂದಿಗೆ, ನಾವು ಕಾರ್ಯಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು ಸೊಗಸಾದ ಮಾರ್ಗವನ್ನು ಪಡೆದುಕೊಂಡಿದ್ದೇವೆ - async/wait operators. ಈ ಪರಿಕಲ್ಪನೆಗಳು ಅಸಮಕಾಲಿಕ ಕೋಡ್ ಅನ್ನು ಸರಳ ಮತ್ತು ಸಿಂಕ್ರೊನಸ್ ಎಂದು ಬರೆಯಲು ಸಾಧ್ಯವಾಗಿಸಿತು, ಇದು ಥ್ರೆಡ್‌ಗಳ ಆಂತರಿಕ ಕಾರ್ಯಗಳ ಬಗ್ಗೆ ಕಡಿಮೆ ತಿಳುವಳಿಕೆಯನ್ನು ಹೊಂದಿರುವ ಜನರಿಗೆ ಅವುಗಳನ್ನು ಬಳಸುವ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಬರೆಯಲು ಸಾಧ್ಯವಾಗಿಸಿತು, ದೀರ್ಘ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ನಿರ್ವಹಿಸುವಾಗ ಫ್ರೀಜ್ ಆಗದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು. async/await ಅನ್ನು ಬಳಸುವುದು ಒಂದು ಅಥವಾ ಹಲವಾರು ಲೇಖನಗಳಿಗೆ ವಿಷಯವಾಗಿದೆ, ಆದರೆ ನಾನು ಅದರ ಸಾರಾಂಶವನ್ನು ಕೆಲವು ವಾಕ್ಯಗಳಲ್ಲಿ ಪಡೆಯಲು ಪ್ರಯತ್ನಿಸುತ್ತೇನೆ:

  • async ಎನ್ನುವುದು ಕಾರ್ಯ ಅಥವಾ ನಿರರ್ಥಕವನ್ನು ಹಿಂದಿರುಗಿಸುವ ವಿಧಾನದ ಪರಿವರ್ತಕವಾಗಿದೆ
  • ಮತ್ತು waiit ಒಂದು ತಡೆರಹಿತ ಕಾರ್ಯ ಕಾಯುವ ಆಪರೇಟರ್ ಆಗಿದೆ.

ಮತ್ತೊಮ್ಮೆ: ಕಾಯುವ ಆಪರೇಟರ್, ಸಾಮಾನ್ಯ ಸಂದರ್ಭದಲ್ಲಿ (ವಿನಾಯಿತಿಗಳಿವೆ), ಪ್ರಸ್ತುತ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆಯ ಥ್ರೆಡ್ ಅನ್ನು ಮತ್ತಷ್ಟು ಬಿಡುಗಡೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ಕಾರ್ಯವು ಅದರ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದಾಗ ಮತ್ತು ಥ್ರೆಡ್ (ವಾಸ್ತವವಾಗಿ, ಸಂದರ್ಭವನ್ನು ಹೇಳಲು ಇದು ಹೆಚ್ಚು ಸರಿಯಾಗಿರುತ್ತದೆ. , ಆದರೆ ಅದರ ನಂತರ ಹೆಚ್ಚು) ವಿಧಾನವನ್ನು ಮತ್ತಷ್ಟು ಕಾರ್ಯಗತಗೊಳಿಸುವುದನ್ನು ಮುಂದುವರಿಸುತ್ತದೆ. .NET ಒಳಗೆ, ಈ ಕಾರ್ಯವಿಧಾನವನ್ನು ಇಳುವರಿ ಆದಾಯದ ರೀತಿಯಲ್ಲಿಯೇ ಅಳವಡಿಸಲಾಗುತ್ತದೆ, ಲಿಖಿತ ವಿಧಾನವು ಸಂಪೂರ್ಣ ವರ್ಗಕ್ಕೆ ತಿರುಗಿದಾಗ, ಇದು ರಾಜ್ಯ ಯಂತ್ರವಾಗಿದೆ ಮತ್ತು ಈ ರಾಜ್ಯಗಳನ್ನು ಅವಲಂಬಿಸಿ ಪ್ರತ್ಯೇಕ ತುಣುಕುಗಳಲ್ಲಿ ಕಾರ್ಯಗತಗೊಳಿಸಬಹುದು. ಆಸಕ್ತಿಯುಳ್ಳ ಯಾರಾದರೂ ಅಸೈನ್ಸ್/ವೇಯ್ಟ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು ಯಾವುದೇ ಸರಳ ಕೋಡ್ ಅನ್ನು ಬರೆಯಬಹುದು, ಕಂಪೈಲರ್ ಜೆನರೇಟೆಡ್ ಕೋಡ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ JetBrains dotPeek ಅನ್ನು ಬಳಸಿಕೊಂಡು ಕಂಪೈಲ್ ಮಾಡಬಹುದು ಮತ್ತು ಅಸೆಂಬ್ಲಿಯನ್ನು ವೀಕ್ಷಿಸಬಹುದು.

ಕಾರ್ಯವನ್ನು ಪ್ರಾರಂಭಿಸಲು ಮತ್ತು ಬಳಸಲು ಆಯ್ಕೆಗಳನ್ನು ನೋಡೋಣ. ಕೆಳಗಿನ ಕೋಡ್ ಉದಾಹರಣೆಯಲ್ಲಿ, ನಾವು ಯಾವುದೇ ಉಪಯುಕ್ತವಲ್ಲದ ಹೊಸ ಕಾರ್ಯವನ್ನು ರಚಿಸುತ್ತೇವೆ (ಥ್ರೆಡ್.ಸ್ಲೀಪ್(10000)), ಆದರೆ ನಿಜ ಜೀವನದಲ್ಲಿ ಇದು ಕೆಲವು ಸಂಕೀರ್ಣ CPU-ತೀವ್ರವಾದ ಕೆಲಸವಾಗಿರಬೇಕು.

using TCO = System.Threading.Tasks.TaskCreationOptions;

public static async void VoidAsyncMethod() {
    var cancellationSource = new CancellationTokenSource();

    await Task.Factory.StartNew(
        // Code of action will be executed on other context
        () => Thread.Sleep(10000),
        cancellationSource.Token,
        TCO.LongRunning | TCO.AttachedToParent | TCO.PreferFairness,
        scheduler
    );

    //  Code after await will be executed on captured context
}

ಹಲವಾರು ಆಯ್ಕೆಗಳೊಂದಿಗೆ ಕಾರ್ಯವನ್ನು ರಚಿಸಲಾಗಿದೆ:

  • ಲಾಂಗ್‌ರನ್ನಿಂಗ್ ಕಾರ್ಯವು ತ್ವರಿತವಾಗಿ ಪೂರ್ಣಗೊಳ್ಳುವುದಿಲ್ಲ ಎಂಬ ಸುಳಿವು, ಇದರರ್ಥ ಪೂಲ್‌ನಿಂದ ಥ್ರೆಡ್ ಅನ್ನು ತೆಗೆದುಕೊಳ್ಳದೆ ಪರಿಗಣಿಸುವುದು ಯೋಗ್ಯವಾಗಿದೆ, ಆದರೆ ಇತರರಿಗೆ ಹಾನಿಯಾಗದಂತೆ ಈ ಕಾರ್ಯಕ್ಕಾಗಿ ಪ್ರತ್ಯೇಕ ಒಂದನ್ನು ರಚಿಸುವುದು.
  • ಲಗತ್ತಿಸಲಾದToParent - ಕಾರ್ಯಗಳನ್ನು ಕ್ರಮಾನುಗತದಲ್ಲಿ ಜೋಡಿಸಬಹುದು. ಈ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿದರೆ, ಕಾರ್ಯವು ಸ್ವತಃ ಪೂರ್ಣಗೊಂಡ ಸ್ಥಿತಿಯಲ್ಲಿರಬಹುದು ಮತ್ತು ಅದರ ಮಕ್ಕಳ ಮರಣದಂಡನೆಗಾಗಿ ಕಾಯುತ್ತಿದೆ.
  • ಆದ್ಯತೆ - ಅಂದರೆ ಕಾರ್ಯಗತಗೊಳಿಸಲು ಕಳುಹಿಸಲಾದ ಕಾರ್ಯಗಳನ್ನು ನಂತರ ಕಳುಹಿಸುವ ಮೊದಲು ಕಾರ್ಯಗತಗೊಳಿಸುವುದು ಉತ್ತಮ. ಆದರೆ ಇದು ಕೇವಲ ಶಿಫಾರಸು ಮತ್ತು ಫಲಿತಾಂಶಗಳನ್ನು ಖಾತರಿಪಡಿಸುವುದಿಲ್ಲ.

ವಿಧಾನಕ್ಕೆ ರವಾನಿಸಲಾದ ಎರಡನೇ ಪ್ಯಾರಾಮೀಟರ್ ರದ್ದು ಟೋಕನ್ ಆಗಿದೆ. ಕಾರ್ಯಾಚರಣೆಯನ್ನು ಪ್ರಾರಂಭಿಸಿದ ನಂತರ ಅದನ್ನು ರದ್ದುಗೊಳಿಸುವುದನ್ನು ಸರಿಯಾಗಿ ನಿರ್ವಹಿಸಲು, ಕಾರ್ಯಗತಗೊಳಿಸಲಾದ ಕೋಡ್ ಅನ್ನು ರದ್ದುಗೊಳಿಸುವಿಕೆ ಟೋಕನ್ ಸ್ಥಿತಿಗೆ ಚೆಕ್‌ಗಳೊಂದಿಗೆ ತುಂಬಿಸಬೇಕು. ಯಾವುದೇ ಪರಿಶೀಲನೆಗಳಿಲ್ಲದಿದ್ದರೆ, ರದ್ದುಮಾಡುವ ಟೋಕನ್‌ಸೋರ್ಸ್ ಆಬ್ಜೆಕ್ಟ್‌ನಲ್ಲಿ ಕರೆಯಲಾದ ರದ್ದು ವಿಧಾನವು ಕಾರ್ಯವನ್ನು ಪ್ರಾರಂಭಿಸುವ ಮೊದಲು ಮಾತ್ರ ಕಾರ್ಯಗತಗೊಳಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ.

ಕೊನೆಯ ನಿಯತಾಂಕವು TaskScheduler ಪ್ರಕಾರದ ಶೆಡ್ಯೂಲರ್ ವಸ್ತುವಾಗಿದೆ. ಈ ವರ್ಗ ಮತ್ತು ಅದರ ವಂಶಸ್ಥರು ಥ್ರೆಡ್‌ಗಳಾದ್ಯಂತ ಕಾರ್ಯಗಳನ್ನು ವಿತರಿಸುವ ತಂತ್ರಗಳನ್ನು ನಿಯಂತ್ರಿಸಲು ವಿನ್ಯಾಸಗೊಳಿಸಲಾಗಿದೆ; ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ, ಪೂಲ್‌ನಿಂದ ಯಾದೃಚ್ಛಿಕ ಥ್ರೆಡ್‌ನಲ್ಲಿ ಕಾರ್ಯವನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗುತ್ತದೆ.

ವೇಯ್ಟ್ ಆಪರೇಟರ್ ಅನ್ನು ರಚಿಸಿದ ಕಾರ್ಯಕ್ಕೆ ಅನ್ವಯಿಸಲಾಗುತ್ತದೆ, ಅಂದರೆ ಅದರ ನಂತರ ಬರೆಯಲಾದ ಕೋಡ್, ಒಂದಿದ್ದರೆ, ನಿರೀಕ್ಷಿಸುವ ಮೊದಲು ಕೋಡ್ ಅನ್ನು ಅದೇ ಸಂದರ್ಭದಲ್ಲಿ (ಸಾಮಾನ್ಯವಾಗಿ ಇದರರ್ಥ ಅದೇ ಥ್ರೆಡ್‌ನಲ್ಲಿ) ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗುತ್ತದೆ.

ವಿಧಾನವನ್ನು ಅಸಿಂಕ್ ನಿರರ್ಥಕ ಎಂದು ಗುರುತಿಸಲಾಗಿದೆ, ಅಂದರೆ ಇದು ನಿರೀಕ್ಷಿಸಿ ಆಪರೇಟರ್ ಅನ್ನು ಬಳಸಬಹುದು, ಆದರೆ ಕರೆ ಮಾಡುವ ಕೋಡ್ ಅನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲು ಕಾಯಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಅಂತಹ ವೈಶಿಷ್ಟ್ಯವು ಅಗತ್ಯವಿದ್ದರೆ, ನಂತರ ವಿಧಾನವು ಕಾರ್ಯವನ್ನು ಹಿಂತಿರುಗಿಸಬೇಕು. ಅಸಿಂಕ್ ಅನೂರ್ಜಿತ ಎಂದು ಗುರುತಿಸಲಾದ ವಿಧಾನಗಳು ತುಂಬಾ ಸಾಮಾನ್ಯವಾಗಿದೆ: ನಿಯಮದಂತೆ, ಇವು ಈವೆಂಟ್ ಹ್ಯಾಂಡ್ಲರ್‌ಗಳು ಅಥವಾ ಬೆಂಕಿಯ ಮೇಲೆ ಕೆಲಸ ಮಾಡುವ ಮತ್ತು ತತ್ವವನ್ನು ಮರೆತುಬಿಡುವ ಇತರ ವಿಧಾನಗಳಾಗಿವೆ. ನೀವು ಮರಣದಂಡನೆಯ ಅಂತ್ಯದವರೆಗೆ ಕಾಯುವ ಅವಕಾಶವನ್ನು ನೀಡುವುದಲ್ಲದೆ, ಫಲಿತಾಂಶವನ್ನು ಹಿಂದಿರುಗಿಸಬೇಕಾದರೆ, ನೀವು ಟಾಸ್ಕ್ ಅನ್ನು ಬಳಸಬೇಕಾಗುತ್ತದೆ.

StartNew ವಿಧಾನವು ಹಿಂತಿರುಗಿದ ಕಾರ್ಯದಲ್ಲಿ, ಹಾಗೆಯೇ ಬೇರೆ ಯಾವುದಾದರೂ, ನೀವು ConfigureAwait ವಿಧಾನವನ್ನು ಸುಳ್ಳು ನಿಯತಾಂಕದೊಂದಿಗೆ ಕರೆಯಬಹುದು, ನಂತರ ಕಾಯುವಿಕೆಯ ನಂತರದ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆಯು ಸೆರೆಹಿಡಿಯಲಾದ ಸಂದರ್ಭದಲ್ಲಿ ಅಲ್ಲ, ಆದರೆ ಅನಿಯಂತ್ರಿತವಾಗಿ ಮುಂದುವರಿಯುತ್ತದೆ. ಕಾಯುವಿಕೆಯ ನಂತರ ಕೋಡ್‌ಗೆ ಮರಣದಂಡನೆಯ ಸಂದರ್ಭವು ಮುಖ್ಯವಲ್ಲದಿದ್ದಾಗ ಇದನ್ನು ಯಾವಾಗಲೂ ಮಾಡಬೇಕು. ಲೈಬ್ರರಿಯಲ್ಲಿ ಪ್ಯಾಕ್ ಮಾಡಲಾದ ಕೋಡ್ ಅನ್ನು ಬರೆಯುವಾಗ ಇದು MS ನಿಂದ ಶಿಫಾರಸು ಮಾಡಲ್ಪಟ್ಟಿದೆ.

ಕಾರ್ಯವನ್ನು ಪೂರ್ಣಗೊಳಿಸಲು ನೀವು ಹೇಗೆ ಕಾಯಬಹುದು ಎಂಬುದರ ಕುರಿತು ಸ್ವಲ್ಪ ಹೆಚ್ಚು ವಾಸಿಸೋಣ. ಕೆಳಗಿನ ಕೋಡ್‌ನ ಉದಾಹರಣೆಯಾಗಿದೆ, ನಿರೀಕ್ಷೆಯನ್ನು ಷರತ್ತುಬದ್ಧವಾಗಿ ಮಾಡಿದಾಗ ಮತ್ತು ಅದನ್ನು ಷರತ್ತುಬದ್ಧವಾಗಿ ಕಳಪೆಯಾಗಿ ಮಾಡಿದಾಗ ಕಾಮೆಂಟ್‌ಗಳೊಂದಿಗೆ.

public static async void AnotherMethod() {

    int result = await AsyncMethod(); // good

    result = AsyncMethod().Result; // bad

    AsyncMethod().Wait(); // bad

    IEnumerable<Task> tasks = new Task[] {
        AsyncMethod(), OtherAsyncMethod()
    };

    await Task.WhenAll(tasks); // good
    await Task.WhenAny(tasks); // good

    Task.WaitAll(tasks.ToArray()); // bad
}

ಮೊದಲ ಉದಾಹರಣೆಯಲ್ಲಿ, ಕರೆ ಮಾಡುವ ಥ್ರೆಡ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸದೆ ಕಾರ್ಯವು ಪೂರ್ಣಗೊಳ್ಳಲು ನಾವು ಕಾಯುತ್ತೇವೆ; ಫಲಿತಾಂಶವು ಈಗಾಗಲೇ ಇದ್ದಾಗ ಮಾತ್ರ ನಾವು ಅದನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಹಿಂತಿರುಗುತ್ತೇವೆ; ಅಲ್ಲಿಯವರೆಗೆ, ಕರೆ ಮಾಡುವ ಥ್ರೆಡ್ ಅನ್ನು ಅದರ ಸ್ವಂತ ಸಾಧನಗಳಿಗೆ ಬಿಡಲಾಗುತ್ತದೆ.

ಎರಡನೆಯ ಆಯ್ಕೆಯಲ್ಲಿ, ವಿಧಾನದ ಫಲಿತಾಂಶವನ್ನು ಲೆಕ್ಕಾಚಾರ ಮಾಡುವವರೆಗೆ ನಾವು ಕರೆ ಮಾಡುವ ಥ್ರೆಡ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸುತ್ತೇವೆ. ಇದು ಕೆಟ್ಟದು ಏಕೆಂದರೆ ನಾವು ಪ್ರೋಗ್ರಾಂನ ಅಂತಹ ಅಮೂಲ್ಯವಾದ ಸಂಪನ್ಮೂಲವನ್ನು ಸರಳವಾದ ಆಲಸ್ಯದಿಂದ ಆಕ್ರಮಿಸಿಕೊಂಡಿದ್ದೇವೆ, ಆದರೆ ನಾವು ಕರೆಯುವ ವಿಧಾನದ ಕೋಡ್ ನಿರೀಕ್ಷಿಸಿ ಹೊಂದಿದ್ದರೆ ಮತ್ತು ಸಿಂಕ್ರೊನೈಸೇಶನ್ ಸಂದರ್ಭವು ನಂತರ ಕರೆ ಮಾಡುವ ಥ್ರೆಡ್‌ಗೆ ಹಿಂತಿರುಗುವ ಅಗತ್ಯವಿದೆ. ನಿರೀಕ್ಷಿಸಿ, ನಂತರ ನಾವು ಡೆಡ್‌ಲಾಕ್ ಪಡೆಯುತ್ತೇವೆ : ಅಸಮಕಾಲಿಕ ವಿಧಾನದ ಫಲಿತಾಂಶವನ್ನು ಲೆಕ್ಕಹಾಕಲು ಕರೆ ಮಾಡುವ ಥ್ರೆಡ್ ಕಾಯುತ್ತದೆ, ಅಸಮಕಾಲಿಕ ವಿಧಾನವು ಕರೆ ಮಾಡುವ ಥ್ರೆಡ್‌ನಲ್ಲಿ ಅದರ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆಯನ್ನು ಮುಂದುವರಿಸಲು ವ್ಯರ್ಥವಾಗಿ ಪ್ರಯತ್ನಿಸುತ್ತದೆ.

ಈ ವಿಧಾನದ ಮತ್ತೊಂದು ಅನನುಕೂಲವೆಂದರೆ ಸಂಕೀರ್ಣ ದೋಷ ನಿರ್ವಹಣೆ. ಸತ್ಯವೆಂದರೆ ಅಸಮಕಾಲಿಕ ಕೋಡ್‌ನಲ್ಲಿ ಅಸಮಕಾಲಿಕ ದೋಷಗಳು ಅಸಿಂಕ್ / ವೇಯ್ಟ್ ಅನ್ನು ಬಳಸುವಾಗ ನಿಭಾಯಿಸಲು ತುಂಬಾ ಸುಲಭ - ಅವು ಕೋಡ್ ಸಿಂಕ್ರೊನಸ್ ಆಗಿದ್ದರೆ ಅದೇ ರೀತಿ ವರ್ತಿಸುತ್ತವೆ. ನಾವು ಕಾರ್ಯವೊಂದಕ್ಕೆ ಸಿಂಕ್ರೊನಸ್ ವೇಯ್ಟ್ ಎಕ್ಸಾರ್ಸಿಸಮ್ ಅನ್ನು ಅನ್ವಯಿಸಿದರೆ, ಮೂಲ ವಿನಾಯಿತಿಯು ಒಟ್ಟು ಎಕ್ಸೆಪ್ಶನ್ ಆಗಿ ಬದಲಾಗುತ್ತದೆ, ಅಂದರೆ. ವಿನಾಯಿತಿಯನ್ನು ನಿರ್ವಹಿಸಲು, ನೀವು InnerException ಪ್ರಕಾರವನ್ನು ಪರೀಕ್ಷಿಸಬೇಕು ಮತ್ತು C# ಜಗತ್ತಿನಲ್ಲಿ ಹೆಚ್ಚು ಪರಿಚಿತವಾಗಿರುವ ಕ್ಯಾಚ್ ಬ್ಲಾಕ್‌ಗಳ ಸರಪಳಿಯ ಬದಲಿಗೆ, ಒಂದು ಕ್ಯಾಚ್ ಬ್ಲಾಕ್‌ನೊಳಗೆ ನೀವೇ ಇಫ್ ಚೈನ್ ಅನ್ನು ಬರೆಯಬೇಕು ಅಥವಾ ನಿರ್ಮಿಸುವಾಗ ಕ್ಯಾಚ್ ಅನ್ನು ಬಳಸಬೇಕು.

ಮೂರನೇ ಮತ್ತು ಅಂತಿಮ ಉದಾಹರಣೆಗಳನ್ನು ಅದೇ ಕಾರಣಕ್ಕಾಗಿ ಕೆಟ್ಟದಾಗಿ ಗುರುತಿಸಲಾಗಿದೆ ಮತ್ತು ಒಂದೇ ರೀತಿಯ ಸಮಸ್ಯೆಗಳನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ.

ಯಾವಾಗ ಎನಿ ಮತ್ತು ಯಾವಾಗ ಎಲ್ಲಾ ವಿಧಾನಗಳು ಕಾರ್ಯಗಳ ಗುಂಪಿಗಾಗಿ ಕಾಯಲು ಅತ್ಯಂತ ಅನುಕೂಲಕರವಾಗಿದೆ; ಅವರು ಕಾರ್ಯಗಳ ಗುಂಪನ್ನು ಒಂದರೊಳಗೆ ಸುತ್ತುತ್ತಾರೆ, ಇದು ಗುಂಪಿನಿಂದ ಕಾರ್ಯವನ್ನು ಮೊದಲು ಪ್ರಚೋದಿಸಿದಾಗ ಅಥವಾ ಅವರೆಲ್ಲರೂ ತಮ್ಮ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದಾಗ ಬೆಂಕಿಯಿಡುತ್ತದೆ.

ಎಳೆಗಳನ್ನು ನಿಲ್ಲಿಸುವುದು

ವಿವಿಧ ಕಾರಣಗಳಿಗಾಗಿ, ಪ್ರಾರಂಭವಾದ ನಂತರ ಹರಿವನ್ನು ನಿಲ್ಲಿಸುವುದು ಅಗತ್ಯವಾಗಬಹುದು. ಇದನ್ನು ಮಾಡಲು ಹಲವಾರು ಮಾರ್ಗಗಳಿವೆ. ಥ್ರೆಡ್ ವರ್ಗವು ಎರಡು ಸೂಕ್ತವಾಗಿ ಹೆಸರಿಸಲಾದ ವಿಧಾನಗಳನ್ನು ಹೊಂದಿದೆ: ಸ್ಥಗಿತಗೊಳಿಸಿ и ಅಡಚಣೆ. ಮೊದಲನೆಯದನ್ನು ಬಳಸಲು ಹೆಚ್ಚು ಶಿಫಾರಸು ಮಾಡುವುದಿಲ್ಲ, ಏಕೆಂದರೆ ಯಾವುದೇ ಯಾದೃಚ್ಛಿಕ ಕ್ಷಣದಲ್ಲಿ ಕರೆ ಮಾಡಿದ ನಂತರ, ಯಾವುದೇ ಸೂಚನೆಯ ಪ್ರಕ್ರಿಯೆಯ ಸಮಯದಲ್ಲಿ, ಒಂದು ವಿನಾಯಿತಿಯನ್ನು ಎಸೆಯಲಾಗುತ್ತದೆ ThreadAbortedException. ಯಾವುದೇ ಪೂರ್ಣಾಂಕ ವೇರಿಯಬಲ್ ಅನ್ನು ಹೆಚ್ಚಿಸುವಾಗ ಅಂತಹ ವಿನಾಯಿತಿಯನ್ನು ಎಸೆಯಲಾಗುವುದು ಎಂದು ನೀವು ನಿರೀಕ್ಷಿಸುವುದಿಲ್ಲ, ಸರಿ? ಮತ್ತು ಈ ವಿಧಾನವನ್ನು ಬಳಸುವಾಗ, ಇದು ಅತ್ಯಂತ ನೈಜ ಪರಿಸ್ಥಿತಿಯಾಗಿದೆ. ಕೋಡ್‌ನ ನಿರ್ದಿಷ್ಟ ವಿಭಾಗದಲ್ಲಿ ಅಂತಹ ವಿನಾಯಿತಿಯನ್ನು ರಚಿಸುವುದರಿಂದ CLR ಅನ್ನು ನೀವು ತಡೆಯಬೇಕಾದರೆ, ನೀವು ಅದನ್ನು ಕರೆಗಳಲ್ಲಿ ಸುತ್ತಿಕೊಳ್ಳಬಹುದು Thread.BeginCriticalRegion, ಥ್ರೆಡ್.ಎಂಡ್ ಕ್ರಿಟಿಕಲ್ ರೀಜನ್. ಅಂತಿಮವಾಗಿ ಬ್ಲಾಕ್‌ನಲ್ಲಿ ಬರೆಯಲಾದ ಯಾವುದೇ ಕೋಡ್ ಅಂತಹ ಕರೆಗಳಲ್ಲಿ ಸುತ್ತುತ್ತದೆ. ಈ ಕಾರಣಕ್ಕಾಗಿ, ಫ್ರೇಮ್‌ವರ್ಕ್ ಕೋಡ್‌ನ ಆಳದಲ್ಲಿ ನೀವು ಖಾಲಿ ಪ್ರಯತ್ನದೊಂದಿಗೆ ಬ್ಲಾಕ್‌ಗಳನ್ನು ಕಾಣಬಹುದು, ಆದರೆ ಅಂತಿಮವಾಗಿ ಖಾಲಿಯಾಗಿಲ್ಲ. ಮೈಕ್ರೋಸಾಫ್ಟ್ ಈ ವಿಧಾನವನ್ನು ಎಷ್ಟು ನಿರುತ್ಸಾಹಗೊಳಿಸುತ್ತದೆ ಎಂದರೆ ಅವರು ಅದನ್ನು .net ಕೋರ್‌ನಲ್ಲಿ ಸೇರಿಸಲಿಲ್ಲ.

ಇಂಟರಪ್ಟ್ ವಿಧಾನವು ಹೆಚ್ಚು ನಿರೀಕ್ಷಿತವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ. ಇದು ವಿನಾಯಿತಿಯೊಂದಿಗೆ ಥ್ರೆಡ್ ಅನ್ನು ಅಡ್ಡಿಪಡಿಸಬಹುದು ಥ್ರೆಡ್ ಇಂಟರಪ್ಟೆಡ್ ಎಕ್ಸೆಪ್ಶನ್ ಥ್ರೆಡ್ ಕಾಯುವ ಸ್ಥಿತಿಯಲ್ಲಿದ್ದಾಗ ಮಾತ್ರ ಆ ಕ್ಷಣಗಳಲ್ಲಿ. WaitHandle, ಲಾಕ್, ಅಥವಾ Thread.Sleep ಗೆ ಕರೆ ಮಾಡಿದ ನಂತರ ನೇತಾಡುತ್ತಿರುವಾಗ ಅದು ಈ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸುತ್ತದೆ.

ಮೇಲೆ ವಿವರಿಸಿದ ಎರಡೂ ಆಯ್ಕೆಗಳು ತಮ್ಮ ಅನಿರೀಕ್ಷಿತತೆಯಿಂದಾಗಿ ಕೆಟ್ಟದಾಗಿವೆ. ರಚನೆಯನ್ನು ಬಳಸುವುದು ಪರಿಹಾರವಾಗಿದೆ ರದ್ದತಿ ಟೋಕನ್ ಮತ್ತು ವರ್ಗ ರದ್ದು ಟೋಕನ್ಸೋರ್ಸ್. ವಿಷಯ ಹೀಗಿದೆ: CancellationTokenSource ವರ್ಗದ ಉದಾಹರಣೆಯನ್ನು ರಚಿಸಲಾಗಿದೆ ಮತ್ತು ಅದನ್ನು ಹೊಂದಿರುವವರು ಮಾತ್ರ ವಿಧಾನವನ್ನು ಕರೆ ಮಾಡುವ ಮೂಲಕ ಕಾರ್ಯಾಚರಣೆಯನ್ನು ನಿಲ್ಲಿಸಬಹುದು ರದ್ದು. ರದ್ದತಿ ಟೋಕನ್ ಅನ್ನು ಮಾತ್ರ ಕಾರ್ಯಾಚರಣೆಗೆ ರವಾನಿಸಲಾಗುತ್ತದೆ. CancellationToken ಮಾಲೀಕರು ಕಾರ್ಯಾಚರಣೆಯನ್ನು ಸ್ವತಃ ರದ್ದುಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ, ಆದರೆ ಕಾರ್ಯಾಚರಣೆಯನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆಯೇ ಎಂಬುದನ್ನು ಮಾತ್ರ ಪರಿಶೀಲಿಸಬಹುದು. ಇದಕ್ಕಾಗಿ ಬೂಲಿಯನ್ ಆಸ್ತಿ ಇದೆ ರದ್ದುಪಡಿಸಲು ವಿನಂತಿಸಲಾಗಿದೆ ಮತ್ತು ವಿಧಾನ ಥ್ರೋIfCancelRequested. ಎರಡನೆಯದು ಒಂದು ವಿನಾಯಿತಿಯನ್ನು ಎಸೆಯುತ್ತದೆ TaskCancelledException ಒಂದು ವೇಳೆ ರದ್ದುಗೊಳಿಸುವ ವಿಧಾನವನ್ನು ರದ್ದುಗೊಳಿಸುವ ಟೋಕನ್ ನಿದರ್ಶನದಲ್ಲಿ ಗಿಳಿ ಎಂದು ಕರೆಯಲಾಗಿದೆ. ಮತ್ತು ನಾನು ಬಳಸಲು ಶಿಫಾರಸು ಮಾಡುವ ವಿಧಾನ ಇದು. ವಿನಾಯಿತಿ ಕಾರ್ಯಾಚರಣೆಯನ್ನು ಯಾವ ಹಂತದಲ್ಲಿ ಸ್ಥಗಿತಗೊಳಿಸಬಹುದು ಎಂಬುದರ ಮೇಲೆ ಸಂಪೂರ್ಣ ನಿಯಂತ್ರಣವನ್ನು ಪಡೆಯುವ ಮೂಲಕ ಹಿಂದಿನ ಆಯ್ಕೆಗಳಿಗಿಂತ ಇದು ಸುಧಾರಣೆಯಾಗಿದೆ.

ಥ್ರೆಡ್ ಅನ್ನು ನಿಲ್ಲಿಸಲು ಅತ್ಯಂತ ಕ್ರೂರ ಆಯ್ಕೆಯೆಂದರೆ Win32 API ಟರ್ಮಿನೇಟ್ ಥ್ರೆಡ್ ಕಾರ್ಯವನ್ನು ಕರೆಯುವುದು. ಈ ಕಾರ್ಯವನ್ನು ಕರೆದ ನಂತರ CLR ನ ನಡವಳಿಕೆಯು ಅನಿರೀಕ್ಷಿತವಾಗಿರಬಹುದು. MSDN ನಲ್ಲಿ ಈ ಕಾರ್ಯದ ಬಗ್ಗೆ ಈ ಕೆಳಗಿನವುಗಳನ್ನು ಬರೆಯಲಾಗಿದೆ: "ಟರ್ಮಿನೇಟ್ ಥ್ರೆಡ್ ಅಪಾಯಕಾರಿ ಕಾರ್ಯವಾಗಿದ್ದು, ಇದನ್ನು ಅತ್ಯಂತ ವಿಪರೀತ ಸಂದರ್ಭಗಳಲ್ಲಿ ಮಾತ್ರ ಬಳಸಬೇಕು. "

FromAsync ವಿಧಾನವನ್ನು ಬಳಸಿಕೊಂಡು ಲೆಗಸಿ API ಅನ್ನು ಟಾಸ್ಕ್ ಆಧಾರಿತವಾಗಿ ಪರಿವರ್ತಿಸಲಾಗುತ್ತಿದೆ

ಕಾರ್ಯಗಳನ್ನು ಪರಿಚಯಿಸಿದ ನಂತರ ಪ್ರಾರಂಭಿಸಿದ ಪ್ರಾಜೆಕ್ಟ್‌ನಲ್ಲಿ ಕೆಲಸ ಮಾಡಲು ನೀವು ಸಾಕಷ್ಟು ಅದೃಷ್ಟವಂತರಾಗಿದ್ದರೆ ಮತ್ತು ಹೆಚ್ಚಿನ ಡೆವಲಪರ್‌ಗಳಿಗೆ ಸ್ತಬ್ಧ ಭಯಾನಕತೆಯನ್ನು ಉಂಟುಮಾಡುವುದನ್ನು ನಿಲ್ಲಿಸಿದರೆ, ನೀವು ಬಹಳಷ್ಟು ಹಳೆಯ APIಗಳೊಂದಿಗೆ ವ್ಯವಹರಿಸಬೇಕಾಗಿಲ್ಲ, ಮೂರನೇ ವ್ಯಕ್ತಿಗಳು ಮತ್ತು ನಿಮ್ಮ ತಂಡದೊಂದಿಗೆ ಹಿಂದೆ ಚಿತ್ರಹಿಂಸೆ ನೀಡಿದ್ದಾರೆ. ಅದೃಷ್ಟವಶಾತ್, .NET ಫ್ರೇಮ್‌ವರ್ಕ್ ತಂಡವು ನಮ್ಮನ್ನು ನೋಡಿಕೊಂಡಿತು, ಆದರೂ ಬಹುಶಃ ನಮ್ಮನ್ನು ನಾವು ನೋಡಿಕೊಳ್ಳುವುದು ಗುರಿಯಾಗಿರಬಹುದು. ಅದು ಇರಲಿ, ಹಳೆಯ ಅಸಮಕಾಲಿಕ ಪ್ರೋಗ್ರಾಮಿಂಗ್ ವಿಧಾನಗಳಲ್ಲಿ ಹೊಸದಕ್ಕೆ ಬರೆಯಲಾದ ಕೋಡ್ ಅನ್ನು ನೋವುರಹಿತವಾಗಿ ಪರಿವರ್ತಿಸಲು .NET ಹಲವಾರು ಸಾಧನಗಳನ್ನು ಹೊಂದಿದೆ. ಅವುಗಳಲ್ಲಿ ಒಂದು TaskFactory ನ FromAsync ವಿಧಾನವಾಗಿದೆ. ಕೆಳಗಿನ ಕೋಡ್ ಉದಾಹರಣೆಯಲ್ಲಿ, ನಾನು ಈ ವಿಧಾನವನ್ನು ಬಳಸಿಕೊಂಡು ಕಾರ್ಯದಲ್ಲಿ WebRequest ವರ್ಗದ ಹಳೆಯ ಅಸಿಂಕ್ ವಿಧಾನಗಳನ್ನು ಸುತ್ತಿಕೊಳ್ಳುತ್ತೇನೆ.

object state = null;
WebRequest wr = WebRequest.CreateHttp("http://github.com");
await Task.Factory.FromAsync(
    wr.BeginGetResponse,
    we.EndGetResponse
);

ಇದು ಕೇವಲ ಒಂದು ಉದಾಹರಣೆಯಾಗಿದೆ ಮತ್ತು ನೀವು ಅಂತರ್ನಿರ್ಮಿತ ಪ್ರಕಾರಗಳೊಂದಿಗೆ ಇದನ್ನು ಮಾಡಲು ಅಸಂಭವವಾಗಿದೆ, ಆದರೆ ಯಾವುದೇ ಹಳೆಯ ಯೋಜನೆಯು ಸರಳವಾಗಿ IAsyncResult ಮತ್ತು EndDoSomething ವಿಧಾನಗಳನ್ನು ಹಿಂದಿರುಗಿಸುವ BeginDoSomething ವಿಧಾನಗಳೊಂದಿಗೆ ತುಂಬಿರುತ್ತದೆ.

TaskCompletionSource ವರ್ಗವನ್ನು ಬಳಸಿಕೊಂಡು ಲೆಗಸಿ API ಅನ್ನು ಟಾಸ್ಕ್ ಆಧಾರಿತವಾಗಿ ಪರಿವರ್ತಿಸಿ

ಪರಿಗಣಿಸಲು ಮತ್ತೊಂದು ಪ್ರಮುಖ ಸಾಧನವೆಂದರೆ ವರ್ಗ TaskCompletionSource. ಕಾರ್ಯಗಳು, ಉದ್ದೇಶ ಮತ್ತು ಕಾರ್ಯಾಚರಣೆಯ ತತ್ವದ ವಿಷಯದಲ್ಲಿ, ಇದು ಥ್ರೆಡ್‌ಪೂಲ್ ವರ್ಗದ RegisterWaitForSingleObject ವಿಧಾನವನ್ನು ಸ್ವಲ್ಪಮಟ್ಟಿಗೆ ನೆನಪಿಸುತ್ತದೆ, ಅದನ್ನು ನಾನು ಮೇಲೆ ಬರೆದಿದ್ದೇನೆ. ಈ ವರ್ಗವನ್ನು ಬಳಸಿಕೊಂಡು, ನೀವು ಕಾರ್ಯಗಳಲ್ಲಿ ಹಳೆಯ ಅಸಮಕಾಲಿಕ API ಗಳನ್ನು ಸುಲಭವಾಗಿ ಮತ್ತು ಅನುಕೂಲಕರವಾಗಿ ಸುತ್ತಿಕೊಳ್ಳಬಹುದು.

ಈ ಉದ್ದೇಶಗಳಿಗಾಗಿ ಉದ್ದೇಶಿಸಲಾದ ಟಾಸ್ಕ್ ಫ್ಯಾಕ್ಟರಿ ವರ್ಗದ FromAsync ವಿಧಾನದ ಬಗ್ಗೆ ನಾನು ಈಗಾಗಲೇ ಮಾತನಾಡಿದ್ದೇನೆ ಎಂದು ನೀವು ಹೇಳುತ್ತೀರಿ. ಕಳೆದ 15 ವರ್ಷಗಳಲ್ಲಿ ಮೈಕ್ರೋಸಾಫ್ಟ್ ನೀಡಿದ .net ನಲ್ಲಿ ಅಸಮಕಾಲಿಕ ಮಾದರಿಗಳ ಅಭಿವೃದ್ಧಿಯ ಸಂಪೂರ್ಣ ಇತಿಹಾಸವನ್ನು ಇಲ್ಲಿ ನಾವು ನೆನಪಿಟ್ಟುಕೊಳ್ಳಬೇಕು: ಟಾಸ್ಕ್-ಬೇಸ್ಡ್ ಅಸಿಂಕ್ರೊನಸ್ ಪ್ಯಾಟರ್ನ್ (TAP) ಗಿಂತ ಮೊದಲು, ಅಸಮಕಾಲಿಕ ಪ್ರೋಗ್ರಾಮಿಂಗ್ ಪ್ಯಾಟರ್ನ್ (APP) ಇತ್ತು. ವಿಧಾನಗಳ ಬಗ್ಗೆ ಆರಂಭಿಸಲುಏನಾದರೂ ಹಿಂತಿರುಗುತ್ತಿದೆ IAsyncResult ಮತ್ತು ವಿಧಾನಗಳು ಕೊನೆಇದನ್ನು ಸ್ವೀಕರಿಸುವ DoSomething ಮತ್ತು ಈ ವರ್ಷಗಳ ಪರಂಪರೆಗೆ FromAsync ವಿಧಾನವು ಪರಿಪೂರ್ಣವಾಗಿದೆ, ಆದರೆ ಕಾಲಾನಂತರದಲ್ಲಿ, ಇದನ್ನು ಈವೆಂಟ್ ಆಧಾರಿತ ಅಸಮಕಾಲಿಕ ಮಾದರಿಯಿಂದ ಬದಲಾಯಿಸಲಾಯಿತು (ಇಎಪಿ), ಇದು ಅಸಮಕಾಲಿಕ ಕಾರ್ಯಾಚರಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದಾಗ ಈವೆಂಟ್ ಅನ್ನು ಎತ್ತಲಾಗುವುದು ಎಂದು ಊಹಿಸಲಾಗಿದೆ.

TaskCompletionSource ಈವೆಂಟ್ ಮಾದರಿಯ ಸುತ್ತಲೂ ನಿರ್ಮಿಸಲಾದ ಕಾರ್ಯಗಳು ಮತ್ತು ಲೆಗಸಿ API ಗಳನ್ನು ಸುತ್ತಲು ಪರಿಪೂರ್ಣವಾಗಿದೆ. ಅದರ ಕೆಲಸದ ಸಾರವು ಕೆಳಕಂಡಂತಿದೆ: ಈ ವರ್ಗದ ವಸ್ತುವು ಟಾಸ್ಕ್ ಪ್ರಕಾರದ ಸಾರ್ವಜನಿಕ ಆಸ್ತಿಯನ್ನು ಹೊಂದಿದೆ, ಅದರ ಸ್ಥಿತಿಯನ್ನು TaskCompletionSource ವರ್ಗದ SetResult, SetException, ಇತ್ಯಾದಿ ವಿಧಾನಗಳ ಮೂಲಕ ನಿಯಂತ್ರಿಸಬಹುದು. ಈ ಕಾರ್ಯಕ್ಕೆ ನಿರೀಕ್ಷಿತ ಆಪರೇಟರ್ ಅನ್ನು ಅನ್ವಯಿಸಿದ ಸ್ಥಳಗಳಲ್ಲಿ, TaskCompletionSource ಗೆ ಅನ್ವಯಿಸಲಾದ ವಿಧಾನವನ್ನು ಅವಲಂಬಿಸಿ ಅದನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗುತ್ತದೆ ಅಥವಾ ವಿನಾಯಿತಿಯೊಂದಿಗೆ ವಿಫಲಗೊಳ್ಳುತ್ತದೆ. ಇದು ಇನ್ನೂ ಸ್ಪಷ್ಟವಾಗಿಲ್ಲದಿದ್ದರೆ, ಈ ಕೋಡ್ ಉದಾಹರಣೆಯನ್ನು ನೋಡೋಣ, ಅಲ್ಲಿ ಕೆಲವು ಹಳೆಯ EAP API ಅನ್ನು TaskCompletionSource ಬಳಸಿಕೊಂಡು ಟಾಸ್ಕ್‌ನಲ್ಲಿ ಸುತ್ತಿಡಲಾಗುತ್ತದೆ: ಈವೆಂಟ್ ಫೈರ್ ಮಾಡಿದಾಗ, ಕಾರ್ಯವನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ ಸ್ಥಿತಿಗೆ ವರ್ಗಾಯಿಸಲಾಗುತ್ತದೆ ಮತ್ತು ನಿರೀಕ್ಷಿಸಿ ಆಪರೇಟರ್ ಅನ್ನು ಅನ್ವಯಿಸುವ ವಿಧಾನ ಈ ಕಾರ್ಯವು ವಸ್ತುವನ್ನು ಸ್ವೀಕರಿಸಿದ ನಂತರ ಅದರ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆಯನ್ನು ಪುನರಾರಂಭಿಸುತ್ತದೆ ಫಲಿತಾಂಶ.

public static Task<Result> DoAsync(this SomeApiInstance someApiObj) {

    var completionSource = new TaskCompletionSource<Result>();
    someApiObj.Done += 
        result => completionSource.SetResult(result);
    someApiObj.Do();

    result completionSource.Task;
}

TaskCompletionSource ಸಲಹೆಗಳು ಮತ್ತು ತಂತ್ರಗಳು

TaskCompletionSource ಅನ್ನು ಬಳಸಿಕೊಂಡು ಹಳೆಯ API ಗಳನ್ನು ಸುತ್ತುವುದು ಅಷ್ಟೆ ಅಲ್ಲ. ಈ ವರ್ಗವನ್ನು ಬಳಸುವುದರಿಂದ ಥ್ರೆಡ್‌ಗಳನ್ನು ಆಕ್ರಮಿಸದ ಕಾರ್ಯಗಳಲ್ಲಿ ವಿವಿಧ API ಗಳನ್ನು ವಿನ್ಯಾಸಗೊಳಿಸುವ ಆಸಕ್ತಿದಾಯಕ ಸಾಧ್ಯತೆಯನ್ನು ತೆರೆಯುತ್ತದೆ. ಮತ್ತು ಸ್ಟ್ರೀಮ್, ನಾವು ನೆನಪಿಟ್ಟುಕೊಳ್ಳುವಂತೆ, ದುಬಾರಿ ಸಂಪನ್ಮೂಲವಾಗಿದೆ ಮತ್ತು ಅವುಗಳ ಸಂಖ್ಯೆ ಸೀಮಿತವಾಗಿದೆ (ಮುಖ್ಯವಾಗಿ RAM ನ ಪ್ರಮಾಣದಿಂದ). ಸಂಕೀರ್ಣ ವ್ಯವಹಾರ ತರ್ಕದೊಂದಿಗೆ ಲೋಡ್ ಮಾಡಲಾದ ವೆಬ್ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಅಭಿವೃದ್ಧಿಪಡಿಸುವ ಮೂಲಕ ಈ ಮಿತಿಯನ್ನು ಸುಲಭವಾಗಿ ಸಾಧಿಸಬಹುದು. ಲಾಂಗ್-ಪೋಲಿಂಗ್‌ನಂತಹ ಟ್ರಿಕ್ ಅನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುವಾಗ ನಾನು ಮಾತನಾಡುವ ಸಾಧ್ಯತೆಗಳನ್ನು ಪರಿಗಣಿಸೋಣ.

ಸಂಕ್ಷಿಪ್ತವಾಗಿ ಹೇಳುವುದಾದರೆ, ಟ್ರಿಕ್‌ನ ಸಾರವು ಹೀಗಿದೆ: ನೀವು API ನಿಂದ ಅದರ ಬದಿಯಲ್ಲಿ ಸಂಭವಿಸುವ ಕೆಲವು ಘಟನೆಗಳ ಬಗ್ಗೆ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಬೇಕು, ಆದರೆ API ಕೆಲವು ಕಾರಣಗಳಿಗಾಗಿ ಈವೆಂಟ್ ಅನ್ನು ವರದಿ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ, ಆದರೆ ರಾಜ್ಯವನ್ನು ಮಾತ್ರ ಹಿಂತಿರುಗಿಸಬಹುದು. ವೆಬ್‌ಸಾಕೆಟ್‌ನ ಸಮಯಕ್ಕಿಂತ ಮೊದಲು ಅಥವಾ ಕೆಲವು ಕಾರಣಗಳಿಂದ ಈ ತಂತ್ರಜ್ಞಾನವನ್ನು ಬಳಸಲು ಅಸಾಧ್ಯವಾದಾಗ HTTP ಮೇಲೆ ನಿರ್ಮಿಸಲಾದ ಎಲ್ಲಾ APIಗಳು ಇವುಗಳ ಉದಾಹರಣೆಗಳಾಗಿವೆ. ಕ್ಲೈಂಟ್ HTTP ಸರ್ವರ್ ಅನ್ನು ಕೇಳಬಹುದು. HTTP ಸರ್ವರ್ ಸ್ವತಃ ಕ್ಲೈಂಟ್ನೊಂದಿಗೆ ಸಂವಹನವನ್ನು ಪ್ರಾರಂಭಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಟೈಮರ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು ಸರ್ವರ್ ಅನ್ನು ಸಮೀಕ್ಷೆ ಮಾಡುವುದು ಸರಳ ಪರಿಹಾರವಾಗಿದೆ, ಆದರೆ ಇದು ಸರ್ವರ್‌ನಲ್ಲಿ ಹೆಚ್ಚುವರಿ ಲೋಡ್ ಅನ್ನು ಸೃಷ್ಟಿಸುತ್ತದೆ ಮತ್ತು ಸರಾಸರಿ ಟೈಮರ್ ಇಂಟರ್‌ವಲ್ / 2 ನಲ್ಲಿ ಹೆಚ್ಚುವರಿ ವಿಳಂಬವನ್ನು ಉಂಟುಮಾಡುತ್ತದೆ. ಇದನ್ನು ಪಡೆಯಲು, ಲಾಂಗ್ ಪೋಲಿಂಗ್ ಎಂಬ ಟ್ರಿಕ್ ಅನ್ನು ಕಂಡುಹಿಡಿಯಲಾಯಿತು, ಇದು ಪ್ರತಿಕ್ರಿಯೆಯನ್ನು ವಿಳಂಬಗೊಳಿಸುತ್ತದೆ ಅವಧಿ ಮುಗಿಯುವವರೆಗೆ ಅಥವಾ ಈವೆಂಟ್ ಸಂಭವಿಸುವವರೆಗೆ ಸರ್ವರ್. ಈವೆಂಟ್ ಸಂಭವಿಸಿದಲ್ಲಿ, ಅದನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲಾಗುತ್ತದೆ, ಇಲ್ಲದಿದ್ದರೆ, ನಂತರ ವಿನಂತಿಯನ್ನು ಮತ್ತೆ ಕಳುಹಿಸಲಾಗುತ್ತದೆ.

while(!eventOccures && !timeoutExceeded)  {

  CheckTimout();
  CheckEvent();
  Thread.Sleep(1);
}

ಆದರೆ ಈವೆಂಟ್‌ಗಾಗಿ ಕಾಯುತ್ತಿರುವ ಗ್ರಾಹಕರ ಸಂಖ್ಯೆ ಹೆಚ್ಚಾದ ತಕ್ಷಣ ಅಂತಹ ಪರಿಹಾರವು ಭಯಾನಕವಾಗಿದೆ ಎಂದು ಸಾಬೀತುಪಡಿಸುತ್ತದೆ, ಏಕೆಂದರೆ... ಅಂತಹ ಪ್ರತಿಯೊಂದು ಕ್ಲೈಂಟ್ ಈವೆಂಟ್‌ಗಾಗಿ ಕಾಯುತ್ತಿರುವ ಸಂಪೂರ್ಣ ಥ್ರೆಡ್ ಅನ್ನು ಆಕ್ರಮಿಸಿಕೊಂಡಿದೆ. ಹೌದು, ಮತ್ತು ಈವೆಂಟ್ ಅನ್ನು ಪ್ರಚೋದಿಸಿದಾಗ ನಾವು ಹೆಚ್ಚುವರಿ 1ms ವಿಳಂಬವನ್ನು ಪಡೆಯುತ್ತೇವೆ, ಹೆಚ್ಚಾಗಿ ಇದು ಗಮನಾರ್ಹವಲ್ಲ, ಆದರೆ ಸಾಫ್ಟ್‌ವೇರ್ ಅನ್ನು ಏಕೆ ಕೆಟ್ಟದಾಗಿ ಮಾಡುತ್ತದೆ? ನಾವು Thread.Sleep (1) ಅನ್ನು ತೆಗೆದುಹಾಕಿದರೆ, ನಂತರ ವ್ಯರ್ಥವಾಗಿ ನಾವು ಒಂದು ಪ್ರೊಸೆಸರ್ ಕೋರ್ ಅನ್ನು 100% ಐಡಲ್ ಅನ್ನು ಲೋಡ್ ಮಾಡುತ್ತೇವೆ, ಅನುಪಯುಕ್ತ ಚಕ್ರದಲ್ಲಿ ತಿರುಗುತ್ತದೆ. TaskCompletionSource ಅನ್ನು ಬಳಸಿಕೊಂಡು ನೀವು ಈ ಕೋಡ್ ಅನ್ನು ಸುಲಭವಾಗಿ ರೀಮೇಕ್ ಮಾಡಬಹುದು ಮತ್ತು ಮೇಲೆ ಗುರುತಿಸಲಾದ ಎಲ್ಲಾ ಸಮಸ್ಯೆಗಳನ್ನು ಪರಿಹರಿಸಬಹುದು:

class LongPollingApi {

    private Dictionary<int, TaskCompletionSource<Msg>> tasks;

    public async Task<Msg> AcceptMessageAsync(int userId, int duration) {

        var cs = new TaskCompletionSource<Msg>();
        tasks[userId] = cs;
        await Task.WhenAny(Task.Delay(duration), cs.Task);
        return cs.Task.IsCompleted ? cs.Task.Result : null;
    }

    public void SendMessage(int userId, Msg m) {

        if (tasks.TryGetValue(userId, out var completionSource))
            completionSource.SetResult(m);
    }
}

ಈ ಕೋಡ್ ಉತ್ಪಾದನೆಗೆ ಸಿದ್ಧವಾಗಿಲ್ಲ, ಆದರೆ ಕೇವಲ ಡೆಮೊ ಆಗಿದೆ. ನೈಜ ಸಂದರ್ಭಗಳಲ್ಲಿ ಅದನ್ನು ಬಳಸಲು, ಯಾರೂ ನಿರೀಕ್ಷಿಸದ ಸಮಯದಲ್ಲಿ ಸಂದೇಶವು ಬಂದಾಗ ಪರಿಸ್ಥಿತಿಯನ್ನು ನಿಭಾಯಿಸಲು ನಿಮಗೆ ಕನಿಷ್ಠ ಅಗತ್ಯವಿರುತ್ತದೆ: ಈ ಸಂದರ್ಭದಲ್ಲಿ, AsseptMessageAsync ವಿಧಾನವು ಈಗಾಗಲೇ ಪೂರ್ಣಗೊಂಡ ಕಾರ್ಯವನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ. ಇದು ಅತ್ಯಂತ ಸಾಮಾನ್ಯವಾದ ಪ್ರಕರಣವಾಗಿದ್ದರೆ, ನೀವು ValueTask ಅನ್ನು ಬಳಸುವ ಬಗ್ಗೆ ಯೋಚಿಸಬಹುದು.

ನಾವು ಸಂದೇಶಕ್ಕಾಗಿ ವಿನಂತಿಯನ್ನು ಸ್ವೀಕರಿಸಿದಾಗ, ನಾವು ನಿಘಂಟಿನಲ್ಲಿ TaskCompletionSource ಅನ್ನು ರಚಿಸುತ್ತೇವೆ ಮತ್ತು ಇರಿಸುತ್ತೇವೆ ಮತ್ತು ನಂತರ ಏನಾಗುತ್ತದೆ ಎಂಬುದನ್ನು ನಿರೀಕ್ಷಿಸಿ: ನಿರ್ದಿಷ್ಟಪಡಿಸಿದ ಸಮಯದ ಮಧ್ಯಂತರವು ಮುಕ್ತಾಯಗೊಳ್ಳುತ್ತದೆ ಅಥವಾ ಸಂದೇಶವನ್ನು ಸ್ವೀಕರಿಸಲಾಗುತ್ತದೆ.

ಮೌಲ್ಯ ಕಾರ್ಯ: ಏಕೆ ಮತ್ತು ಹೇಗೆ

ಅಸಿಂಕ್/ವೇಯ್ಟ್ ಆಪರೇಟರ್‌ಗಳು, ಇಳುವರಿ ರಿಟರ್ನ್ ಆಪರೇಟರ್‌ನಂತೆ, ವಿಧಾನದಿಂದ ರಾಜ್ಯ ಯಂತ್ರವನ್ನು ಉತ್ಪಾದಿಸುತ್ತದೆ ಮತ್ತು ಇದು ಹೊಸ ವಸ್ತುವಿನ ರಚನೆಯಾಗಿದೆ, ಇದು ಯಾವಾಗಲೂ ಮುಖ್ಯವಲ್ಲ, ಆದರೆ ಅಪರೂಪದ ಸಂದರ್ಭಗಳಲ್ಲಿ ಇದು ಸಮಸ್ಯೆಯನ್ನು ಉಂಟುಮಾಡಬಹುದು. ಈ ಪ್ರಕರಣವು ನಿಜವಾಗಿಯೂ ಆಗಾಗ್ಗೆ ಕರೆಯಲ್ಪಡುವ ವಿಧಾನವಾಗಿರಬಹುದು, ನಾವು ಸೆಕೆಂಡಿಗೆ ಹತ್ತಾರು ಮತ್ತು ನೂರಾರು ಸಾವಿರ ಕರೆಗಳ ಬಗ್ಗೆ ಮಾತನಾಡುತ್ತಿದ್ದೇವೆ. ಅಂತಹ ವಿಧಾನವನ್ನು ಬರೆಯಲಾಗಿದ್ದರೆ ಹೆಚ್ಚಿನ ಸಂದರ್ಭಗಳಲ್ಲಿ ಅದು ಎಲ್ಲಾ ನಿರೀಕ್ಷೆಯ ವಿಧಾನಗಳನ್ನು ಬೈಪಾಸ್ ಮಾಡುವ ಫಲಿತಾಂಶವನ್ನು ಹಿಂದಿರುಗಿಸುತ್ತದೆ, ಆಗ .NET ಇದನ್ನು ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲು ಒಂದು ಸಾಧನವನ್ನು ಒದಗಿಸುತ್ತದೆ - ValueTask ರಚನೆ. ಅದನ್ನು ಸ್ಪಷ್ಟಪಡಿಸಲು, ಅದರ ಬಳಕೆಯ ಉದಾಹರಣೆಯನ್ನು ನೋಡೋಣ: ನಾವು ಆಗಾಗ್ಗೆ ಹೋಗುವ ಸಂಗ್ರಹವಿದೆ. ಅದರಲ್ಲಿ ಕೆಲವು ಮೌಲ್ಯಗಳಿವೆ ಮತ್ತು ನಂತರ ನಾವು ಅವುಗಳನ್ನು ಸರಳವಾಗಿ ಹಿಂತಿರುಗಿಸುತ್ತೇವೆ; ಇಲ್ಲದಿದ್ದರೆ, ಅವುಗಳನ್ನು ಪಡೆಯಲು ನಾವು ಕೆಲವು ನಿಧಾನ IO ಗೆ ಹೋಗುತ್ತೇವೆ. ನಾನು ಎರಡನೆಯದನ್ನು ಅಸಮಕಾಲಿಕವಾಗಿ ಮಾಡಲು ಬಯಸುತ್ತೇನೆ, ಅಂದರೆ ಸಂಪೂರ್ಣ ವಿಧಾನವು ಅಸಮಕಾಲಿಕವಾಗಿ ಹೊರಹೊಮ್ಮುತ್ತದೆ. ಹೀಗಾಗಿ, ವಿಧಾನವನ್ನು ಬರೆಯಲು ಸ್ಪಷ್ಟವಾದ ಮಾರ್ಗವು ಈ ಕೆಳಗಿನಂತಿರುತ್ತದೆ:

public async Task<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return val;
    return await RequestById(id);
}

ಸ್ವಲ್ಪ ಆಪ್ಟಿಮೈಜ್ ಮಾಡುವ ಬಯಕೆ ಮತ್ತು ಈ ಕೋಡ್ ಅನ್ನು ಕಂಪೈಲ್ ಮಾಡುವಾಗ ರೋಸ್ಲಿನ್ ಏನನ್ನು ಉತ್ಪಾದಿಸುತ್ತಾರೆ ಎಂಬ ಸ್ವಲ್ಪ ಭಯದಿಂದಾಗಿ, ನೀವು ಈ ಉದಾಹರಣೆಯನ್ನು ಈ ಕೆಳಗಿನಂತೆ ಪುನಃ ಬರೆಯಬಹುದು:

public Task<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return Task.FromResult(val);
    return RequestById(id);
}

ವಾಸ್ತವವಾಗಿ, ಈ ಸಂದರ್ಭದಲ್ಲಿ ಸೂಕ್ತವಾದ ಪರಿಹಾರವೆಂದರೆ ಹಾಟ್-ಪಾತ್ ಅನ್ನು ಆಪ್ಟಿಮೈಜ್ ಮಾಡುವುದು, ಅವುಗಳೆಂದರೆ, ಯಾವುದೇ ಅನಗತ್ಯ ಹಂಚಿಕೆಗಳಿಲ್ಲದೆ ನಿಘಂಟಿನಿಂದ ಮೌಲ್ಯವನ್ನು ಪಡೆಯುವುದು ಮತ್ತು GC ಯಲ್ಲಿ ಲೋಡ್ ಮಾಡುವುದು, ಆ ಅಪರೂಪದ ಸಂದರ್ಭಗಳಲ್ಲಿ ನಾವು ಇನ್ನೂ ಡೇಟಾಕ್ಕಾಗಿ IO ಗೆ ಹೋಗಬೇಕಾದಾಗ , ಎಲ್ಲವೂ ಹಳೆಯ ರೀತಿಯಲ್ಲಿ ಪ್ಲಸ್/ಮೈನಸ್ ಆಗಿ ಉಳಿಯುತ್ತದೆ:

public ValueTask<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return new ValueTask<string>(val);
    return new ValueTask<string>(RequestById(id));
}

ಈ ಕೋಡ್‌ನ ತುಣುಕನ್ನು ಹತ್ತಿರದಿಂದ ನೋಡೋಣ: ಸಂಗ್ರಹದಲ್ಲಿ ಮೌಲ್ಯವಿದ್ದರೆ, ನಾವು ರಚನೆಯನ್ನು ರಚಿಸುತ್ತೇವೆ, ಇಲ್ಲದಿದ್ದರೆ ನಿಜವಾದ ಕಾರ್ಯವನ್ನು ಅರ್ಥಪೂರ್ಣವಾಗಿ ಸುತ್ತಿಕೊಳ್ಳಲಾಗುತ್ತದೆ. ಈ ಕೋಡ್ ಅನ್ನು ಯಾವ ಮಾರ್ಗದಲ್ಲಿ ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗಿದೆ ಎಂಬುದನ್ನು ಕರೆ ಮಾಡುವ ಕೋಡ್ ಕಾಳಜಿ ವಹಿಸುವುದಿಲ್ಲ: C# ಸಿಂಟ್ಯಾಕ್ಸ್ ದೃಷ್ಟಿಕೋನದಿಂದ ValueTask, ಈ ಸಂದರ್ಭದಲ್ಲಿ ಸಾಮಾನ್ಯ ಕಾರ್ಯದಂತೆ ವರ್ತಿಸುತ್ತದೆ.

ಟಾಸ್ಕ್ ಶೆಡ್ಯೂಲರ್‌ಗಳು: ಕಾರ್ಯ ಉಡಾವಣಾ ತಂತ್ರಗಳನ್ನು ನಿರ್ವಹಿಸುವುದು

ನಾನು ಪರಿಗಣಿಸಲು ಬಯಸುವ ಮುಂದಿನ API ವರ್ಗವಾಗಿದೆ ಟಾಸ್ಕ್ ಶೆಡ್ಯೂಲರ್ ಮತ್ತು ಅದರ ಉತ್ಪನ್ನಗಳು. ಥ್ರೆಡ್‌ಗಳಾದ್ಯಂತ ಕಾರ್ಯಗಳನ್ನು ವಿತರಿಸಲು ತಂತ್ರಗಳನ್ನು ನಿರ್ವಹಿಸುವ ಸಾಮರ್ಥ್ಯವನ್ನು TPL ಹೊಂದಿದೆ ಎಂದು ನಾನು ಈಗಾಗಲೇ ಮೇಲೆ ಉಲ್ಲೇಖಿಸಿದ್ದೇನೆ. ಟಾಸ್ಕ್ ಶೆಡ್ಯೂಲರ್ ವರ್ಗದ ವಂಶಸ್ಥರಲ್ಲಿ ಇಂತಹ ತಂತ್ರಗಳನ್ನು ವ್ಯಾಖ್ಯಾನಿಸಲಾಗಿದೆ. ನಿಮಗೆ ಅಗತ್ಯವಿರುವ ಯಾವುದೇ ತಂತ್ರವನ್ನು ಲೈಬ್ರರಿಯಲ್ಲಿ ಕಾಣಬಹುದು. ಸಮಾನಾಂತರ ವಿಸ್ತರಣೆಗಳು, ಮೈಕ್ರೋಸಾಫ್ಟ್ ಅಭಿವೃದ್ಧಿಪಡಿಸಿದೆ, ಆದರೆ .NET ನ ಭಾಗವಲ್ಲ, ಆದರೆ Nuget ಪ್ಯಾಕೇಜ್‌ನಂತೆ ಸರಬರಾಜು ಮಾಡಲಾಗಿದೆ. ಅವುಗಳಲ್ಲಿ ಕೆಲವನ್ನು ಸಂಕ್ಷಿಪ್ತವಾಗಿ ನೋಡೋಣ:

  • CurrentThreadTaskScheduler - ಪ್ರಸ್ತುತ ಥ್ರೆಡ್‌ನಲ್ಲಿ ಕಾರ್ಯಗಳನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುತ್ತದೆ
  • LimitedConcurrencyLevelTaskScheduler - ಕನ್‌ಸ್ಟ್ರಕ್ಟರ್‌ನಲ್ಲಿ ಅಂಗೀಕರಿಸಲ್ಪಟ್ಟ ಪ್ಯಾರಾಮೀಟರ್ N ಮೂಲಕ ಏಕಕಾಲದಲ್ಲಿ ಕಾರ್ಯಗತಗೊಳಿಸಲಾದ ಕಾರ್ಯಗಳ ಸಂಖ್ಯೆಯನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ
  • ಆರ್ಡರ್ ಮಾಡಿದ ಟಾಸ್ಕ್ ಶೆಡ್ಯೂಲರ್ — LimitedConcurrencyLevelTaskScheduler(1) ಎಂದು ವ್ಯಾಖ್ಯಾನಿಸಲಾಗಿದೆ, ಆದ್ದರಿಂದ ಕಾರ್ಯಗಳನ್ನು ಅನುಕ್ರಮವಾಗಿ ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗುತ್ತದೆ.
  • ವರ್ಕ್ ಸ್ಟೀಲಿಂಗ್ ಟಾಸ್ಕ್ ಶೆಡ್ಯೂಲರ್ - ಅಳವಡಿಸುತ್ತದೆ ಕೆಲಸ-ಕಳ್ಳತನ ಕಾರ್ಯ ವಿತರಣೆಯ ವಿಧಾನ. ಮೂಲಭೂತವಾಗಿ ಇದು ಪ್ರತ್ಯೇಕ ಥ್ರೆಡ್‌ಪೂಲ್ ಆಗಿದೆ. .NET ThreadPool ನಲ್ಲಿ ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಒಂದು ಸ್ಥಿರ ವರ್ಗವಾಗಿದೆ, ಅಂದರೆ ಪ್ರೋಗ್ರಾಂನ ಒಂದು ಭಾಗದಲ್ಲಿ ಅದರ ಓವರ್‌ಲೋಡ್ ಅಥವಾ ತಪ್ಪಾದ ಬಳಕೆಯು ಮತ್ತೊಂದು ಅಡ್ಡ ಪರಿಣಾಮಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು ಎಂಬ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸುತ್ತದೆ. ಇದಲ್ಲದೆ, ಅಂತಹ ದೋಷಗಳ ಕಾರಣವನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು ತುಂಬಾ ಕಷ್ಟ. ಅದು. ಥ್ರೆಡ್‌ಪೂಲ್ ಬಳಕೆಯು ಆಕ್ರಮಣಕಾರಿ ಮತ್ತು ಅನಿರೀಕ್ಷಿತವಾಗಿರಬಹುದಾದ ಪ್ರೋಗ್ರಾಂನ ಭಾಗಗಳಲ್ಲಿ ಪ್ರತ್ಯೇಕ ವರ್ಕ್‌ಸ್ಟೀಲಿಂಗ್‌ಟಾಸ್ಕ್ ಶೆಡ್ಯೂಲರ್‌ಗಳನ್ನು ಬಳಸುವ ಅಗತ್ಯವಿರಬಹುದು.
  • QueuedTaskScheduler — ಆದ್ಯತೆಯ ಸರತಿ ನಿಯಮಗಳ ಪ್ರಕಾರ ಕಾರ್ಯಗಳನ್ನು ನಿರ್ವಹಿಸಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ
  • ThreadPerTaskScheduler - ಅದರ ಮೇಲೆ ಕಾರ್ಯಗತಗೊಳಿಸಲಾದ ಪ್ರತಿಯೊಂದು ಕಾರ್ಯಕ್ಕೂ ಪ್ರತ್ಯೇಕ ಥ್ರೆಡ್ ಅನ್ನು ರಚಿಸುತ್ತದೆ. ಪೂರ್ಣಗೊಳ್ಳಲು ಅನಿರೀಕ್ಷಿತವಾಗಿ ದೀರ್ಘ ಸಮಯ ತೆಗೆದುಕೊಳ್ಳುವ ಕಾರ್ಯಗಳಿಗೆ ಉಪಯುಕ್ತವಾಗಬಹುದು.

ಉತ್ತಮ ವಿವರವಿದೆ ಲೇಖನ ಮೈಕ್ರೋಸಾಫ್ಟ್ ಬ್ಲಾಗ್‌ನಲ್ಲಿ ಟಾಸ್ಕ್ ಶೆಡ್ಯೂಲರ್‌ಗಳ ಬಗ್ಗೆ.

ಕಾರ್ಯಗಳಿಗೆ ಸಂಬಂಧಿಸಿದ ಎಲ್ಲದರ ಅನುಕೂಲಕರ ಡೀಬಗ್ ಮಾಡಲು, ವಿಷುಯಲ್ ಸ್ಟುಡಿಯೋ ಕಾರ್ಯಗಳ ವಿಂಡೋವನ್ನು ಹೊಂದಿದೆ. ಈ ವಿಂಡೋದಲ್ಲಿ ನೀವು ಕಾರ್ಯದ ಪ್ರಸ್ತುತ ಸ್ಥಿತಿಯನ್ನು ನೋಡಬಹುದು ಮತ್ತು ಪ್ರಸ್ತುತ ಕಾರ್ಯಗತಗೊಳ್ಳುತ್ತಿರುವ ಕೋಡ್‌ಗೆ ಹೋಗಬಹುದು.

.NET: ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್ ಮತ್ತು ಅಸಿಂಕ್ರೊನಿಯೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವ ಪರಿಕರಗಳು. ಭಾಗ 1

PLinq ಮತ್ತು ಸಮಾನಾಂತರ ವರ್ಗ

ಕಾರ್ಯಗಳು ಮತ್ತು ಅವುಗಳ ಬಗ್ಗೆ ಹೇಳಲಾದ ಎಲ್ಲದರ ಜೊತೆಗೆ, .NET ನಲ್ಲಿ ಇನ್ನೂ ಎರಡು ಆಸಕ್ತಿದಾಯಕ ಪರಿಕರಗಳಿವೆ: PLinq (Linq2Parallel) ಮತ್ತು ಸಮಾನಾಂತರ ವರ್ಗ. ಮೊದಲನೆಯದು ಬಹು ಥ್ರೆಡ್‌ಗಳಲ್ಲಿ ಎಲ್ಲಾ ಲಿಂಕ್ ಕಾರ್ಯಾಚರಣೆಗಳ ಸಮಾನಾಂತರ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆಯನ್ನು ಭರವಸೆ ನೀಡುತ್ತದೆ. WithDegreeOfParallelism ವಿಸ್ತರಣೆ ವಿಧಾನವನ್ನು ಬಳಸಿಕೊಂಡು ಥ್ರೆಡ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡಬಹುದು. ದುರದೃಷ್ಟವಶಾತ್, PLinq ಅದರ ಡೀಫಾಲ್ಟ್ ಮೋಡ್‌ನಲ್ಲಿ ಗಮನಾರ್ಹ ವೇಗದ ಲಾಭವನ್ನು ಒದಗಿಸಲು ನಿಮ್ಮ ಡೇಟಾ ಮೂಲದ ಆಂತರಿಕ ಕುರಿತು ಸಾಕಷ್ಟು ಮಾಹಿತಿಯನ್ನು ಹೊಂದಿಲ್ಲ, ಮತ್ತೊಂದೆಡೆ, ಪ್ರಯತ್ನಿಸುವ ವೆಚ್ಚವು ತುಂಬಾ ಕಡಿಮೆಯಾಗಿದೆ: ನೀವು ಮೊದಲು AsParallel ವಿಧಾನವನ್ನು ಕರೆಯಬೇಕಾಗುತ್ತದೆ. ಲಿಂಕ್ ವಿಧಾನಗಳ ಸರಣಿ ಮತ್ತು ಕಾರ್ಯಕ್ಷಮತೆ ಪರೀಕ್ಷೆಗಳನ್ನು ನಡೆಸುತ್ತದೆ. ಇದಲ್ಲದೆ, ವಿಭಾಗಗಳ ಕಾರ್ಯವಿಧಾನವನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಡೇಟಾ ಮೂಲದ ಸ್ವರೂಪದ ಬಗ್ಗೆ ಹೆಚ್ಚುವರಿ ಮಾಹಿತಿಯನ್ನು PLinq ಗೆ ರವಾನಿಸಲು ಸಾಧ್ಯವಿದೆ. ನೀವು ಹೆಚ್ಚು ಓದಬಹುದು ಇಲ್ಲಿ и ಇಲ್ಲಿ.

ಸಮಾನಾಂತರ ಸ್ಥಿರ ವರ್ಗವು ಫೋರ್ಚ್ ಸಂಗ್ರಹಣೆಯ ಮೂಲಕ ಸಮಾನಾಂತರವಾಗಿ ಪುನರಾವರ್ತನೆ ಮಾಡುವ ವಿಧಾನಗಳನ್ನು ಒದಗಿಸುತ್ತದೆ, ಫಾರ್ ಲೂಪ್ ಅನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುವುದು ಮತ್ತು ಸಮಾನಾಂತರ ಇನ್ವೊಕ್‌ನಲ್ಲಿ ಬಹು ಪ್ರತಿನಿಧಿಗಳನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುವುದು. ಲೆಕ್ಕಾಚಾರಗಳು ಪೂರ್ಣಗೊಳ್ಳುವವರೆಗೆ ಪ್ರಸ್ತುತ ಥ್ರೆಡ್ನ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆಯನ್ನು ನಿಲ್ಲಿಸಲಾಗುತ್ತದೆ. ಥ್ರೆಡ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಕೊನೆಯ ಆರ್ಗ್ಯುಮೆಂಟ್‌ನಂತೆ ParallelOptions ಅನ್ನು ರವಾನಿಸುವ ಮೂಲಕ ಕಾನ್ಫಿಗರ್ ಮಾಡಬಹುದು. ಆಯ್ಕೆಗಳನ್ನು ಬಳಸಿಕೊಂಡು ನೀವು TaskScheduler ಮತ್ತು CancellationToken ಅನ್ನು ಸಹ ನಿರ್ದಿಷ್ಟಪಡಿಸಬಹುದು.

ಸಂಶೋಧನೆಗಳು

ನನ್ನ ವರದಿಯ ಸಾಮಗ್ರಿಗಳು ಮತ್ತು ಅದರ ನಂತರ ನನ್ನ ಕೆಲಸದ ಸಮಯದಲ್ಲಿ ನಾನು ಸಂಗ್ರಹಿಸಿದ ಮಾಹಿತಿಯನ್ನು ಆಧರಿಸಿ ನಾನು ಈ ಲೇಖನವನ್ನು ಬರೆಯಲು ಪ್ರಾರಂಭಿಸಿದಾಗ, ಇದು ತುಂಬಾ ಇರುತ್ತದೆ ಎಂದು ನಾನು ನಿರೀಕ್ಷಿಸಿರಲಿಲ್ಲ. ಈಗ, ನಾನು ಈ ಲೇಖನವನ್ನು ಟೈಪ್ ಮಾಡುತ್ತಿರುವ ಪಠ್ಯ ಸಂಪಾದಕರು 15 ನೇ ಪುಟವು ಹೋಗಿದೆ ಎಂದು ನಿಂದನೀಯವಾಗಿ ಹೇಳಿದಾಗ, ನಾನು ಮಧ್ಯಂತರ ಫಲಿತಾಂಶಗಳನ್ನು ಸಂಕ್ಷಿಪ್ತಗೊಳಿಸುತ್ತೇನೆ. ಇತರ ತಂತ್ರಗಳು, APIಗಳು, ದೃಶ್ಯ ಪರಿಕರಗಳು ಮತ್ತು ಮೋಸಗಳನ್ನು ಮುಂದಿನ ಲೇಖನದಲ್ಲಿ ಚರ್ಚಿಸಲಾಗುವುದು.

ತೀರ್ಮಾನಗಳು:

  • ಆಧುನಿಕ PC ಗಳ ಸಂಪನ್ಮೂಲಗಳನ್ನು ಬಳಸಲು ಥ್ರೆಡ್ಗಳು, ಅಸಮಕಾಲಿಕತೆ ಮತ್ತು ಸಮಾನಾಂತರತೆಯೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವ ಸಾಧನಗಳನ್ನು ನೀವು ತಿಳಿದುಕೊಳ್ಳಬೇಕು.
  • .NET ಈ ಉದ್ದೇಶಗಳಿಗಾಗಿ ಹಲವು ವಿಭಿನ್ನ ಸಾಧನಗಳನ್ನು ಹೊಂದಿದೆ
  • ಅವೆಲ್ಲವೂ ಏಕಕಾಲದಲ್ಲಿ ಕಾಣಿಸಿಕೊಂಡಿಲ್ಲ, ಆದ್ದರಿಂದ ನೀವು ಹೆಚ್ಚಾಗಿ ಪರಂಪರೆಯನ್ನು ಕಾಣಬಹುದು, ಆದಾಗ್ಯೂ, ಹಳೆಯ API ಗಳನ್ನು ಹೆಚ್ಚು ಪ್ರಯತ್ನವಿಲ್ಲದೆ ಪರಿವರ್ತಿಸುವ ಮಾರ್ಗಗಳಿವೆ.
  • .NET ನಲ್ಲಿ ಥ್ರೆಡ್‌ಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವುದನ್ನು ಥ್ರೆಡ್ ಮತ್ತು ಥ್ರೆಡ್‌ಪೂಲ್ ತರಗತಿಗಳು ಪ್ರತಿನಿಧಿಸುತ್ತವೆ
  • Thread.Abort, Thread.Interrupt, ಮತ್ತು Win32 API TerminateThread ವಿಧಾನಗಳು ಅಪಾಯಕಾರಿ ಮತ್ತು ಬಳಕೆಗೆ ಶಿಫಾರಸು ಮಾಡಲಾಗಿಲ್ಲ. ಬದಲಿಗೆ, CancellationToken ಯಾಂತ್ರಿಕ ವ್ಯವಸ್ಥೆಯನ್ನು ಬಳಸುವುದು ಉತ್ತಮ
  • ಹರಿವು ಅಮೂಲ್ಯವಾದ ಸಂಪನ್ಮೂಲವಾಗಿದೆ ಮತ್ತು ಅದರ ಪೂರೈಕೆ ಸೀಮಿತವಾಗಿದೆ. ಈವೆಂಟ್‌ಗಳಿಗಾಗಿ ಥ್ರೆಡ್‌ಗಳು ನಿರತವಾಗಿರುವ ಸಂದರ್ಭಗಳನ್ನು ತಪ್ಪಿಸಬೇಕು. ಇದಕ್ಕಾಗಿ TaskCompletionSource ವರ್ಗವನ್ನು ಬಳಸಲು ಅನುಕೂಲಕರವಾಗಿದೆ
  • ಸಮಾನಾಂತರತೆ ಮತ್ತು ಅಸಮಕಾಲಿಕತೆಯೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು ಅತ್ಯಂತ ಶಕ್ತಿಶಾಲಿ ಮತ್ತು ಸುಧಾರಿತ .NET ಉಪಕರಣಗಳು ಕಾರ್ಯಗಳಾಗಿವೆ.
  • c# ಅಸಿಂಕ್/ವೇಯ್ಟ್ ಆಪರೇಟರ್‌ಗಳು ತಡೆರಹಿತ ಕಾಯುವಿಕೆಯ ಪರಿಕಲ್ಪನೆಯನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುತ್ತವೆ
  • TaskScheduler-ಪಡೆದ ತರಗತಿಗಳನ್ನು ಬಳಸಿಕೊಂಡು ಥ್ರೆಡ್‌ಗಳಾದ್ಯಂತ ಕಾರ್ಯಗಳ ವಿತರಣೆಯನ್ನು ನೀವು ನಿಯಂತ್ರಿಸಬಹುದು
  • ವ್ಯಾಲ್ಯೂಟಾಸ್ಕ್ ರಚನೆಯು ಹಾಟ್-ಪಾತ್‌ಗಳು ಮತ್ತು ಮೆಮೊರಿ-ಟ್ರಾಫಿಕ್ ಅನ್ನು ಅತ್ಯುತ್ತಮವಾಗಿಸಲು ಉಪಯುಕ್ತವಾಗಿದೆ
  • ವಿಷುಯಲ್ ಸ್ಟುಡಿಯೋದ ಕಾರ್ಯಗಳು ಮತ್ತು ಥ್ರೆಡ್ ವಿಂಡೋಗಳು ಬಹು-ಥ್ರೆಡ್ ಅಥವಾ ಅಸಮಕಾಲಿಕ ಕೋಡ್ ಅನ್ನು ಡೀಬಗ್ ಮಾಡಲು ಸಾಕಷ್ಟು ಉಪಯುಕ್ತ ಮಾಹಿತಿಯನ್ನು ಒದಗಿಸುತ್ತದೆ
  • PLinq ಒಂದು ತಂಪಾದ ಸಾಧನವಾಗಿದೆ, ಆದರೆ ಇದು ನಿಮ್ಮ ಡೇಟಾ ಮೂಲದ ಬಗ್ಗೆ ಸಾಕಷ್ಟು ಮಾಹಿತಿಯನ್ನು ಹೊಂದಿಲ್ಲದಿರಬಹುದು, ಆದರೆ ವಿಭಜನಾ ಕಾರ್ಯವಿಧಾನವನ್ನು ಬಳಸಿಕೊಂಡು ಇದನ್ನು ಸರಿಪಡಿಸಬಹುದು
  • ಮುಂದುವರೆಸಲು ...

ಮೂಲ: www.habr.com

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ