´ë¹®    
FindPage  |  TitleIndex  |  UserPreferences  |  [http]me2day  |  redpixel
RecentChanges
 


Proactor

Contents

1 °³¿ä
2 ÃëÁö
3 µ¿±â
3.1 °í¼º´É ¼­¹öÀÇ Àǹ̰ú ´É·Â
3.2 ÀüÅëÀûÀÎ µ¿½Ã󸮹æ½Ä ¼­¹ö¸ðµ¨µéÀÇ ÀϹÝÀûÀÎ µ£°ú ÇÔÁ¤µé
3.2.1 ´ÙÁß µ¿±âÈ­ ¾²·¹µå¸¦ ÅëÇÑ µ¿½Ãó¸®
3.2.2 ¹ÝÀÀÀû(reactive) À̺¥Æ® µð½ºÆÐĪÀ» ÅëÇÑ µ¿½Ãó¸®
3.3 ÇØ°áÃ¥ : proactive 󸮸¦ ÅëÇÑ µ¿½Ãó¸®
4 Àû¿ëÇØ¾ß ÇÒ °æ¿ì
5 ±¸Á¶¿Í ±¸¼º¿ä¼Òµé
6 Collaborations
7 °á·Ð
7.1 ÀåÁ¡
7.2 ´ÜÁ¡
8 ±¸Çö
8.1 ºñµ¿±â ¸í·É ÇÁ·Î¼¼¼­ÀÇ ±¸Çö
8.1.1 ºñµ¿±â ¸í·É API¸¦ Á¤ÀÇÇϱâ
8.1.2 ºñµ¿±â ó¸® ¿£ÁøÀÇ ±¸Çö
8.2 Implementing the Completion Dispatcher
8.2.1 Implementing Callbacks
8.2.2 Defining Completion Dispatcher Concurrency Strategies
8.3 Implementing Completion Handlers
8.3.1 State Integrity
8.3.2 Resource Management
8.3.3 Preemptive Policy
9 Sample Code
10 Known Uses
11 Related Patterns
12 Concluding Remarks
13 References
13.1 A. Alternative Implementations
13.1.1 A.1 Multiple Synchronous Threads
13.1.2 A.2 Single-threaded Reactive Event Dispatching
  • Proactor - An Object Behavioral Pattern for Demultiplexing and Dispatching Handlers for Asynchronous Events
  • ¿øº»¸µÅ© : [http]http://www.cs.wustl.edu/~schmidt/PDF/proactor.pdf
  • ¿øÀúÀÚ : Irfan Pyarali, Tim Harrison, Douglas C. Schmidt, Thomas D. Jordan
  • proactor¿¡ ´ëÇÑ ±×³ª¸¶ ±¸ÇÒ ¼ö ÀÖ´Â À¯ÀÏÇÑ ³í¹®ÀÔ´Ï´Ù. =_=a ³ª¸§´ë·Î ¹ø¿ªÇϱâ·Î Çß½À´Ï´Ù. ¿øº»ÀÌ PDF¶ó ¿Å±â´Âµ¥ Àå³­¾Æ´Õ´Ï´Ù. -_-;;;

1 °³¿ä #

Çö´ëÀÇ ¿î¿µÃ¼°èµéÀº µ¿½Ã½ÇÇà¿¡ ±âÃÊÇÑ ¾îÇø®ÄÉÀ̼Ç(¼­¹ö)¸¦ °³¹ßÇÏ´Â °ÍÀ» Áö¿øÇϱâ À§ÇØ ¿©·¯°¡Áö ¸ÅÄ¿´ÏÁòµéÀ» Á¦°øÇÑ´Ù. µ¿±âÀû ¸ÖƼ¾²·¹µùÀº ¿©·¯ µ¿ÀÛÀÌ µ¿½Ã´Ù¹ßÀûÀ¸·Î ½ÇÇàµÇ´Â ¾îÇø®ÄÉÀ̼ÇÀ» °³¹ßÇϴµ¥ À־ ÀαâÀÖ´Â ¸ÅÄ¿´ÏÁòÀÌ´Ù. ±×·¸Áö¸¸ ¾²·¹µå´Â Á¾Á¾ ³ôÀº ¼º´É °úºÎÇϸ¦ °¡Áú ¶§°¡ ÀÖ°í, µ¿±âÈ­ ÆÐÅϰú ¹ýÄ¢µé¿¡ ´ëÇÑ ±íÀº Áö½ÄÀ» ¿ä±¸ÇÑ´Ù. ±×·¯¹Ç·Î, ¿©·¯ ¿î¿µÃ¼°èµéÀº µ¿½Ã½ÇÇà 󸮿¡ À־ ¸ÖƼ¾²·¹µùÀÇ °úºÎÇϳª º¹ÀâµµÀÇ ´ëºÎºÐÀ» ¿ÏÈ­½ÃŰ´Â ÀåÁ¡ÀÌ ÀÖ´Â ºñµ¿±âÀû ¸ÅÄ¿´ÏÁòÀ» Áö¿øÇÑ´Ù.

ÀÌ ³í¹®¿¡¼­ Á¦½ÃÇÏ´Â proactor ÆÐÅÏÀº ¿î¿µÃ¼°è¿¡ ÀÇÇØ Á¦°øµÇ´Â ºñµ¿±â ¸ÅÄ¿´ÏÁòµéÀ» È¿À²ÀûÀ¸·Î ´Ù·ç´Â ¾îÇø®ÄÉÀ̼ǰú ½Ã½ºÅÛÀ» ±¸ÃàÇÏ´Â ¹ý¿¡ ´ëÇØ¼­ ¼³¸íÇϰí ÀÖ´Ù. ¾îÇø®ÄÉÀ̼ÇÀÌ ºñµ¿±âÀûÀÎ ÀÛ¾÷À» ¼öÇàÇÒ ¶§, ¿î¿µÃ¼°è´Â ¾îÇø®ÄÉÀ̼ÇÀ» ´ë½ÅÇÏ¿© ÀÛ¾÷À» ½ÇÇàÇÑ´Ù. À̰ÍÀº ¾îÇø®ÄÉÀ̼ÇÀ¸·Î ÇÏ¿©±Ý ÇÊ¿äÇÑ ¸¸Å­ÀÇ ¼öÀÇ ¾²·¹µå¸¦ °¡Áú ÇÊ¿ä¾øÀÌ µ¿½Ã¿¡ µ¿ÀÛÇÏ´Â ´Ù¼öÀÇ µ¿ÀÛÀ» ½ÇÇàÇÒ ¼ö ÀÖ°Ô ÇØÁØ´Ù. µû¶ó¼­, proactor ÆÐÅÏÀº ¼­¹ö ÇÁ·Î±×·¡¹ÖÀ» ´Ü¼øÈ­ ½ÃÄÑÁÖ¸ç, ºñµ¿±â 󸮸¦ À§ÇÑ ¿î¿µÃ¼°èÀÇ Áö¿ø¿¡ ÀÇÁ¸ÇÏ°í º¸´Ù ÀûÀº ¾²·¹µå¸¦ ¿ä±¸ÇÏ°Ô µÊÀ¸·Î½á ¼º´ÉÀ» ÁõÁø½ÃÄÑÁÖ°Ô µÈ´Ù.

2 ÃëÁö #

proactor ÆÐÅÏÀº ºñµ¿±â À̺¥Æ®µéÀÇ ¿Ï·á½ÃÁ¡¿¡ ½ÇÇàµÇ´Â ´ÙÁß À̺¥Æ® Çڵ鷯µéÀÇ µð½ºÆÐΰú µð¸ÖƼÇ÷¢½ÌÀ» Áö¿øÇÑ´Ù. ÀÌ ÆÐÅÏÀº ¿Ï·á À̺¥Æ®µéÀÇ µð¸ÖƼÇ÷¢½ÌÀ» ÅëÇÕÇÏ°í ±×¿¡ ¾Ë¸ÂÀº À̺¥Æ® Çڵ鷯µéÀ» µð½ºÆÐĪÇÏ´Â °ÍÀ» Áö¿øÇÔÀ¸·Î½á ºñµ¿±â±â¹ÝÀÇ ¾îÇø®ÄÉÀÌ¼Ç °³¹ßÀ» ´Ü¼øÈ­ÇØÁØ´Ù.

3 µ¿±â #

ÀÌ ¼½¼ÇÀº proactor ÆÐÅÏÀ» »ç¿ëÇϱâ À§ÇÑ °³³ä°ú µ¿±â¸¦ ±â¼úÇÑ´Ù.

3.1 °í¼º´É ¼­¹öÀÇ Àǹ̰ú ´É·Â #

µ¿±âÀûÀÎ ¹æ½ÄÀÇ ¸ÖƼ¾²·¹µå ȤÀº ¹ÝÀÀÀûÀÎ(reactive) ÇÁ·Î±×·¡¹Ö»ó¿¡¼­ Á¦¾à¾øÀÌ µ¿½Ã󸮹æ½ÄÀ¸·Î ÀÛ¾÷µéÀ» ½ÇÇà½ÃŰ·Á Çϴµ¥ ¼º´É»óÀÇ ÀÕÁ¡ÀÌ ¿ä±¸µÉ ¶§¿¡´Â proactor ÆÐÅÏÀ» »ç¿ëÇÑ´Ù. ÀÌ ÀÕÁ¡µéÀ» ¼³¸íÇϱâ À§Çؼ­ µ¿½Ã󸮹æ½ÄÀ¸·Î ´ÙÁßÀÇ Ã³¸®¸¦ ½ÇÇàÇÒ Çʿ䰡 ÀÖ´Â ³×Æ®¿öÅ© ¾îÇø®ÄÉÀ̼ÇÀ» °í·ÁÇÏÀÚ. ¿¹¸¦ µéÀÚ¸é, °í¼º´ÉÀÇ À¥¼­¹ö´Â ¹Ýµå½Ã ¿©·¯°³ÀÇ Å¬¶óÀÌ¾ðÆ® [1, 2]·ÎºÎÅÍ º¸³»¾îÁø HTTP ¿äûµéÀ» µ¿½Ã¿¡ ó¸®Çؾ߸¸ ÇÑ´Ù. "Figure 1"Àº À¥ºê¶ó¿ìÁ®µé°ú À¥¼­¹ö»çÀÌÀÇ ÀüÇüÀûÀÎ »óÈ£ÀÛ¿ë°ü°è¸¦ º¸¿©ÁØ´Ù. »ç¿ëÀÚ°¡ ºê¶ó¿ìÁ®¿¡°Ô URLÀ» ¿­µµ·Ï Áö½ÃÇϸé, ºê¶ó¿ìÁ®´Â HTTP GET ¿äûÀ» À¥ ¼­¹ö·Î º¸³½´Ù. ¿äûÀ» Á¢¼öÇÏ¸é ¼­¹ö´Â ¿äûÀ» ÆÄ½ÌÇϰí Àû¹ýÇÑÁö °Ë»çÇÑ ÈÄ, ÁöÁ¤µÈ È­ÀÏ(µé)À» ºê¶ó¿ìÁ®·Î µÇµ¹·Á º¸³½´Ù.

proactor_figure_1.png

°í¼º´ÉÀÇ À¥¼­¹ö°¡ °³¹ßµÇ±â À§Çؼ­´Â ´ÙÀ½ ´É·ÂµéÀ» °¡Á®¾ßÇÑ´Ù:
  • µ¿½Ãó¸®(Concurrency); ¼­¹ö´Â µ¿½Ã¿¡ ¿©·¯°³ÀÇ Å¬¶óÀÌ¾ðÆ® ¿äûÀ» ¼öÇàÇØ¾ß¸¸ ÇÑ´Ù.
  • È¿À²¼º(Efficiency); ¼­¹ö´Â Áö¿¬(latency)À» ÃÖ¼ÒÈ­ÇØ¾ßÇϰí, ´ë¿ªÆøÀ» ÃÖ´ë·Î Ȱ¿ëÇØ¾ß Çϸç, ºÒÇÊ¿äÇÏ°Ô CPU(µé)À» µ¿ÀÛ½ÃŰ´Â °ÍÀ» ÇÇÇØ¾ßÇÑ´Ù.
  • ÇÁ·Î±×·¡¹Ö ´Ü¼øÈ­(Programming simplicity); ¼­¹öÀÇ µðÀÚÀÎÀº È¿À²ÀûÀÎ µ¿½Ã󸮿¡ ´ëÇÑ ¿î¿µ Àü·«ÀÇ Àû¿ëÀ» ´Ü¼øÈ­ÇÒ ¼ö ÀÖ¾î¾ß ÇÑ´Ù.
  • ÀûÀÀ¼º(Adaptability); ½Å±Ô ȤÀº °³¼±µÈ Æ®·£½ºÆ÷Æ® ÇÁ·ÎÅäÄÝ(HTTP 1.1°ú °°Àº)À» Áö¿øÇϴµ¥ À־ ÃÖ¼ÒÇÑÀÇ °ü¸® ºñ¿ëÀÌ µéµµ·Ï ÇØ¾ßÇÑ´Ù.

À¥¼­¹ö´Â ¸î°¡Áö µ¿½Ãó¸® Àü·«(´ÙÁß µ¿±âÈ­µÈ ¾²·¹µå¹æ½Ä, reactiveÇÑ µ¿±âÀû À̺¥Æ® µð½ºÆÐĪ, proactiveÇÑ ºñµ¿±â À̺¥Æ® µð½ºÆÐĪ)µéÀ» »ç¿ëÇÏ¿© ±¸ÇöµÉ ¼ö ÀÖ´Ù. ¾Æ·¡¿¡¼­ ¿ì¸®´Â ÀüÅëÀûÀÎ Á¢±Ù ¹æ½ÄÀÇ °áÁ¡À» ã¾Æº¸°í ¾î¶»°Ô proactor ÆÐÅÏÀÌ °í¼º´ÉÀÇ ¼­¹ö ¾îÇø®ÄÉÀ̼ǿ¡ ´ëÇÑ È¿À²ÀûÀ̰í À¯¿¬ÇÑ ºñµ¿±â À̺¥Æ® µð½ºÆÐĪ Àü·«À» Áö¿øÇÏ´Â °­·ÂÇÑ ÅÂÅ©´ÐÀ» Á¦°øÇÏ´ÂÁö »ìÆìº¼ °ÍÀÌ´Ù.

3.2 ÀüÅëÀûÀÎ µ¿½Ã󸮹æ½Ä ¼­¹ö¸ðµ¨µéÀÇ ÀϹÝÀûÀÎ µ£°ú ÇÔÁ¤µé #

µ¿±âÈ­µÈ ¸ÖƼ¾²·¹µù°ú reactiveÇÑ ÇÁ·Î±×·¡¹ÖÀº µ¿½Ã󸮸¦ ±¸ÇöÇÏ´Â ÀϹÝÀûÀÎ ¹æ¹ýÀÌ´Ù. ÀÌ ÀåÀº ÀÌ ÇÁ·Î±×·¡¹Ö ¸ðµ¨µé¿¡ ´ëÇÑ °áÁ¡µéÀ» ¼³¸íÇÑ´Ù.

3.2.1 ´ÙÁß µ¿±âÈ­ ¾²·¹µå¸¦ ÅëÇÑ µ¿½Ãó¸® #

¾Æ¸¶µµ ´ëºÎºÐÀÇ µ¿½Ã󸮹æ½ÄÀÇ À¥¼­¹ö¸¦ ±¸ÇöÇÏ´Â Á÷°üÀûÀÎ ¹æ¹ýÀº µ¿±âÀûÀÎ ¸ÖƼ¾²·¹µù ¹æ½ÄÀÌ´Ù. ÀÌ ¸ðµ¨¿¡¼­´Â ´ÙÁß ¼­¹ö ¾²·¹µåµéÀÌ µ¿½Ã¿¡ ¿©·¯ Ŭ¶óÀÌ¾ðÆ®·Î ºÎÅÍ HTTP GET ¿äûÀ» ó¸®ÇÑ´Ù. °¢ ¾²·¹µå´Â Á¢¼Ó ±¸ÃàÀ» ½ÇÇàÇϰí, HTTP ¿äûÀ» Àаí, ¿äûÀ» ÆÄ½ÌÇϸç, È­ÀÏ Àü¼Û 󸮸¦ µ¿±âÀûÀ¸·Î ¼öÇàÇÑ´Ù. °á°úÀûÀ¸·Î °¢ ó¸®´Â ÇØ´ç 󸮰¡ ¿Ï·áµÉ ¶§ ±îÁö ºí·°´çÇÑ´Ù.

µ¿±âÈ­µÈ ¾²·¹µù ¹æ½ÄÀÇ ÁÖµÈ ÀÕÁ¡Àº ¾îÇø®ÄÉÀÌ¼Ç ÄÚµåÀÇ ´Ü¼øÇÔÀÌ´Ù. Ưº°ÇÑ °æ¿ì, Ŭ¶óÀÌ¾ðÆ® AÀÇ ¿äûÀ» ¼­ºñ½ºÇϱâÀ§ÇØ À¥¼­¹ö¿¡ ÀÇÇØ ½ÇÇàµÇ´Â 󸮵éÀº Ŭ¶óÀÌ¾ðÆ® BÀÇ ¿äûÀ» ¼­ºñ½ºÇϱâ À§ÇÑ Ã³¸®¿Í´Â ´ëºÎºÐ µ¶¸³ÀûÀÌ´Ù. µû¶ó¼­, ¾²·¹µå°£¿¡ °øÀ¯µÇ´Â »óŵéÀÇ ¾çÀÌ Àû±â ¶§¹®¿¡ º°µµÀÇ ¾²·¹µå»ó¿¡¼­ ¼­·Î ´Ù¸¥ ¿äûµéÀ» ¼­ºñ½ºÇÏ´Â °ÍÀÌ ½¬¿î °ÍÀÌ´Ù. (À̰ÍÀº µ¿±âÈ­ÀÇ Çʿ伺À» ÃÖ¼ÒÈ­ÇÏ´Â ¿äÀÎÀÌ´Ù) °Ô´Ù°¡, º°µµÀÇ ¾²·¹µå»ó¿¡¼­ ¾îÇø®ÄÉÀÌ¼Ç ·ÎÁ÷À» ½ÇÇàÇÏ´Â °ÍÀº °³¹ßÀÚ·Î ÇÏ¿©±Ý ¼øÂ÷ÀûÀÎ ¸í·Éµé°ú ºí·ÏÅ· 󸮸¦ ´Ù·ç´Â °ÍÀ» Çã¿ëÇÑ´Ù.

proactor_figure_2.png

"Figure 2"´Â ¾î¶»°Ô µ¿±âÀûÀÎ ¾²·¹µå¸¦ »ç¿ëÇÏ¿© µðÀÚÀÎµÈ À¥¼­¹ö°¡ ¿©·¯°³ÀÇ Å¬¶óÀÌ¾ðÆ®µéÀ» µ¿½Ã½ÇÇà¹æ½ÄÀ¸·Î ó¸®ÇÒ ¼ö ÀÖ´ÂÁö º¸¿©ÁØ´Ù. ÀÌ figure´Â Sync Acceptor°¡ µ¿±âÀûÀ¸·Î ³×Æ®¿öÅ© Á¢¼ÓÀ» accept ó¸®ÇϱâÀ§ÇÑ ¼­¹öÃø ±¸Á¶¸¦ ÀºÆóÇϰí(encapsulate)ÀÖ´Ù´Â °ÍÀ» º¸¿©ÁØ´Ù. "¿¬°á 1°³´ç ¾²·¹µå 1°³" ¹æ½ÄÀ» »ç¿ëÇØ¼­ HTTP GET ¿äûÀ» ¼­ºñ½ºÇϱâÀ§ÇÑ °¢°¢ÀÇ ¾²·¹µåµéÀÇ ½ÇÇà´Ü°è´Â ´ÙÀ½°ú °°ÀÌ ¿ä¾àµÉ ¼ö ÀÖ´Ù:

  1. °¢ ¾²·¹µå´Â accept()ÇÔ¼ö½ÇÇà½Ã Ŭ¶óÀÌ¾ðÆ® Á¢¼Ó¿äûÀÌ ¿Ã¶§±îÁö µ¿±âÀûÀ¸·Î ºí·Ï´çÇÑ´Ù.
  2. Ŭ¶óÀÌ¾ðÆ®°¡ ¼­¹ö¿¡ ¿¬°áµÇ¸é, Á¢¼ÓÀÌ acceptµÈ´Ù. (ºí·°ÀÌ Ç®¸°´Ù)
  3. »õ·Î Á¢¼ÓµÈ Ŭ¶óÀ̾ðÆ®ÀÇ HTTP ¿äûÀÌ µ¿±âÀûÀ¸·Î ³×Æ®¿öÅ© ¿¬°áÀ» ÅëÇÏ¿© ÀÐÇôÁø´Ù.
  4. ¿äûÀ» ÆÄ½ÌÇÑ´Ù.
  5. ¿äûµÈ È­ÀÏÀ» µ¿±âÀûÀ¸·Î Àд´Ù.
  6. È­ÀÏÀÇ ³»¿ëÀÌ µ¿±âÀûÀ¸·Î Ŭ¶óÀÌ¾ðÆ®¿¡°Ô Àü¼ÛµÈ´Ù.

µ¿±âÀû ¾²·¹µå ¸ðµ¨À» Àû¿ëÇÑ À¥¼­¹ö¸¦ C++ ÄÚµå ¿¹Á¦¸¦ ºÎ·Ï A.1¿¡ ÷ºÎÇØ³õ¾Ò´Ù. ¾Õ¿¡¼­ ±â¼úÇß´ø °Íó·³, °¢°¢¿¡ ¿¬°áµÈ Ŭ¶óÀÌ¾ðÆ®´Â Àü´ã(dedicated) ¼­¹ö ¾²·¹µå¿¡ ÀÇÇØ µ¿½Ãó¸®ÀûÀ¸·Î ¼­ºñ½ºµÈ´Ù. ¾²·¹µå´Â ´Ù¸¥ HTTP ¿äûÀ» ¼­ºñ½ºÇϱâ Àü¿¡ µ¿±âÀûÀ¸·Î ¿äû¹ÞÀº 󸮸¦ ¿Ï·áÇÑ´Ù. ±×·¯¹Ç·Î, ¿©·¯ Ŭ¶óÀÌ¾ðÆ®¿¡ ´ëÇØ ¼­ºñ½ºÇϴµ¿¾È µ¿±âÀû ÀÔÃâ·ÂÀ» ½ÇÇàÇÏ·Á¸é, À¥¼­¹ö´Â ´ÙÁß ¾²·¹µå¸¦ »ý¼ºÇؾ߸¸ ÇÑ´Ù. ÀÌ µ¿±âÀû ¸ÖƼ¾²·¹µå ¸ðµ¨ÀÌ Á÷°üÀûÀ̰í, ºñ±³Àû È¿°úÀûÀ¸·Î ´ÙÁß CPU ü°è¿¡¼­ ¸ÅÇεȴٰí ÇÒÁö¶óµµ, À̰ÍÀº ´ÙÀ½°ú °°Àº ´ÜÁ¡µéÀ» °¡Áø´Ù:

  • ¾²·¹µù Á¤Ã¥ÀÌ µ¿½Ãó¸® Á¤Ã¥°ú °­ÇÏ°Ô ¿¬°üµÇ¾îÀÖ´Ù. : ÀÌ ±¸Á¶´Â °¢ ¿¬°áµÈ Ŭ¶óÀÌ¾ðÆ®µéÀ» À§ÇÑ °³º°ÀûÀÎ Àü´ã ¾²·¹µå¸¦ ÇÊ¿ä·Î ÇÑ´Ù. µ¿½Ã󸮹æ½ÄÀÇ ¾îÇø®ÄÉÀ̼ÇÀº µ¿½Ã¿¡ ¼­ºñ½ºµÇ´Â Ŭ¶óÀ̾ðÆ®ÀÇ ¼öº¸´Ù´Â »ç¿ë°¡´ÉÇÑ ÀÚ¿ø(¾²·¹µå Ç®¸µÀ» ÅëÇÑ CPUÀÇ ¼ö¿Í °°Àº °Í)¿¡ ¾²·¹µù Àü·«À» ¸ÂÃß´Â °Í¿¡ ÀÇÇØ º¸´Ù ´õ ÃÖÀûÈ­µÉ ¼ö ÀÖ´Ù.
  • µ¿±âÈ­ÀÇ º¹Àâµµ Áõ°¡ : ¾²·¹µå 󸮴 - ¼­¹öÀÇ °øÀ¯ ÀÚ¿øµé(ij½¬µÈ È­ÀÏÀ̳ª À¥ ÆäÀÌÁöÀÇ È÷Æ®¼ö ±â·Ïµîµî)¿¡ ´ëÇÑ ¾ï¼¼½º¸¦ Á÷·ÄÈ­ÇϱâÀ§Çؼ­ ÇÊ¿äÇÑ - µ¿±âÈ­ ü°è¿¡ ´ëÇÑ º¹Àâµµ¸¦ Áõ°¡½ÃŲ´Ù.
  • ¼º´É»óÀÇ °úºÎÇÏ Áõ°¡ : ¾²·¹µå 󸮴 ÄÁÅýºÆ® ½ºÀ§Äª, µ¿±âÈ­, CPU°£ÀÇ µ¥ÀÌŸ À̵¿µî¿¡ ±âÀÎÇÏ¿© °úºÎÇÏ»óÅ·Π½ÇÇàµÉ ¼ö ÀÖ´Ù.;
  • ºñȣȯ¼º: ¾²·¹µå´Â ¸ðµç ¿î¿µÃ¼°è¿¡ °¡´ÉÇÏÁö ¾ÊÀ» ¼öµµ ÀÖ´Ù. °Ô´Ù°¡, ¿î¿µÃ¼°è´Â ¼±Á¡Çü ±×¸®°í ºñ¼±Á¡Çü ¾²·¹µåÀÇ °ßÁö¿¡¼­ º¸¾ÒÀ» °æ¿ì »ó´çÈ÷ Â÷À̰¡ ÀÖ´Ù. ÀÌ·± ÀÌÀ¯·Î, ¿î¿µÃ¼°è Ç÷¿Æû¿¡ »ó°ü¾øÀÌ µ¿ÀÏÇÏ°Ô µ¿ÀÛÇÏ´Â ´ÙÁß ¾²·¹µå¹æ½ÄÀÇ ¼­¹ö¸¦ ¸¸µå´Â °ÍÀº ¿©·Á¿î ÀÏÀÌ´Ù.

ÀÌ·± ´ÜÁ¡µé ¶§¹®¿¡, ¸ÖƼ¾²·¹µùÀº µ¿½Ãó¸® ¹æ½ÄÀÇ À¥¼­¹ö¸¦ °³¹ßÇϴµ¥ À־´Â Á¾Á¾ ¾ÆÁÖ È¿À²ÀûÀÌÁöµµ ¾Ê°í ±¸Á¶°¡ ±×¸® °£´ÜÇÏÁöµµ ¾ÊÀº ¼Ö·ç¼ÇÀÌ µÇ°í ÀÖ´Ù.

3.2.2 ¹ÝÀÀÀû(reactive) À̺¥Æ® µð½ºÆÐĪÀ» ÅëÇÑ µ¿½Ãó¸® #

¶Ç´Ù¸¥ µ¿±âÀû¹æ½ÄÀÇ À¥¼­¹ö¸¦ ±¸ÇöÇÏ´Â ÀϹÝÀûÀÎ ¹æ¹ýÀº ¹ÝÀÀÀû(reactive) À̺¥Æ® µð½ºÆÐĪ ¸ðµ¨À» »ç¿ëÇÏ´Â °ÍÀÌ´Ù. reactor ÆÐÅÏÀº ¾î¶»°Ô ¾îÇø®ÄÉÀ̼ÇÀÌ Initiation Dispatcher¸¦ »ç¿ëÇÏ¿© À̺¥Æ® Çڵ鷯¸¦ µî·ÏÇÒ ¼ö ÀÖ´ÂÁö º¸¿©ÁØ´Ù. Initiation Dispatcher´Â ºí·ÏÅ· ¾øÀÌ ¸í·ÉÀÌ ÀÔȸ(initiate)°¡´ÉÇÒ °æ¿ì ±×¿¡ ¾Ë¸Â´Â À̺¥Æ® Çڵ鷯¸¦ ¾Ë·ÁÁØ´Ù. The Initiation Dispatcher notifies the Event Handler when it is possible to initiate an operation without blocking. ½Ì±Û¾²·¹µå ±â¹ÝÀÇ µ¿½Ãó¸® ¹æ½Ä À¥¼­¹ö´Â reactive À̺¥Æ® µð½ºÆÐĪ ¸ðµ¨À» »ç¿ëÇÒ ¼ö ÀÖ´Ù. (ÀÌ ¸ðµ¨Àº reactor°¡ ¾Ë¸ÂÀº ¸í·ÉÀÌ µé¾î¿ÔÀ½À» ¾Ë·ÁÁÙ ¶§ ±îÁö À̺¥Æ® ·çÇÁ»ó¿¡¼­ ±â´Ù¸®´Â ±¸Á¶¸¦ °¡Áø´Ù.) À¥¼­¹ö»óÀÇ reactive ¸í·É¿¡ ´ëÇÑ ¿¹´Â Initiation DispatcherÀ» »ç¿ëÇÑ acceptorÀÇ µî·ÏÀÛ¾÷ÀÌ´Ù. µ¥ÀÌŸ°¡ ³×Æ®¿öÅ© ¿¬°áÀ» ÅëÇØ¼­ µµÂøÇϸé, µð½ºÆÐÃÄ´Â acceptor¸¦ ÄݹéÇÑ´Ù. acceptor´Â ³×Æ®¿öÅ© ¿¬°áÀ» ¼ö¶ôÇϰí HTTP Çڵ鷯¸¦ »ý¼ºÇÑ´Ù. ±×·± ´ÙÀ½ ÀÌ HTTP Çڵ鷯´Â À¥¼­¹öÀÇ ½Ì±Û¾²·¹µå Á¦¾îÇÏ¿¡¼­ ¹æ±Ý ÁøÇàµÇ´Â ¿¬°á·Î Àü¼ÛµÇ¾î¿Â URL ¿äûÀ» ó¸®Çϱâ À§ÇØ reactor¿¡ µî·ÏµÈ´Ù.

figure 3°ú 4´Â ¹ÝÀÀÀû À̺¥Æ® µð½ºÆäĪÀ» »ç¿ëÇÏ¿© µðÀÚÀÎµÈ À¥¼­¹ö°¡ ¿©·¯°³ÀÇ Å¬¶óÀÌ¾ðÆ®¸¦ ¾î¶»°Ô ´Ù·ç´ÂÁö¸¦ º¸¿©ÁØ´Ù. figure 3´Â À¥¼­¹ö·Î Ŭ¶óÀÌ¾ðÆ®°¡ Á¢¼ÓÇÒ¶§ ¹â°ÔµÇ´Â ´Ü°è¸¦ º¸¿©ÁÖ¸ç, figure 4´Â À¥¼­¹ö°¡ ¾î¶»°Ô Ŭ¶óÀÌ¾ðÆ® ¿äûÀ» ó¸®ÇÏ´ÂÁö º¸¿©ÁØ´Ù.

proactor_figure_3.png

figure 3ÀÇ ´Ü°è´Â ´ÙÀ½°ú °°ÀÌ ¿ä¾àµÉ ¼ö ÀÖ´Ù:

  1. À¥¼­¹ö´Â ½Å±Ô Á¢¼ÓÀ» acceptó¸®Çϱâ À§ÇÑ Initiation Dispatcher¿¡ acceptor¸¦ µî·ÏÇÑ´Ù. (The Web Server registers an Acceptor with the Initiation Dispatcher to accept new connections.)
  2. À¥¼­¹ö´Â Initiation DispatcherÀÇ À̺¥Æ®·çÇÁ¸¦ µ¿ÀÛ½ÃŲ´Ù.
  3. Ŭ¶óÀÌ¾ðÆ®°¡ À¥¼­¹ö¿¡ Á¢¼ÓÇÑ´Ù.
  4. acceptor°¡ ½Å±Ô Á¢¼ÓÀÇ ¹ß»ý¿©ºÎ¸¦ Initiation Dispatcher¿¡°Ô ¾Ë·ÁÁÖ°í acceptor´Â ½Å±Ô Á¢¼ÓÀ» ¹Þ¾ÆµéÀδÙ.
  5. acceptor´Â ½Å±Ô Ŭ¶óÀÌ¾ðÆ®¿¡ ¼­ºñ½ºÇϱâÀ§ÇØ HTTP Çڵ鷯¸¦ »ý¼ºÇÑ´Ù.
  6. HTTP Çڵ鷯´Â Ŭ¶óÀ̾ðÆ®ÀÇ ¿äû µ¥ÀÌŸ¸¦ ÀбâÀ§ÇØ Initiation Dispatcher¿¡ Á¢¼ÓÁ¤º¸¸¦ µî·ÏÇÑ´Ù. (´Ù½Ã¸»Çϸé, Á¢¼Ó»óŸ¦ "Àбâ´ë±â"¸ðµå·Î ¼³Á¤ÇÑ´Ù.)
  7. HTTP Çڵ鷯 ¼­ºñ½º´Â ½Å±Ô Ŭ¶óÀÌ¾ðÆ®·ÎºÎÅÍÀÇ ¿äû¿¡ µû¶ó ¼­ºñ½º¸¦ ½ÃÀÛÇÑ´Ù.

proactor_figure_4.png

±×¸² 4´Â reactive À¥¼­¹ö°¡ HTTP GET ¿äûÀ» ¼­ºñ½ºÇÏ´Â ´Ü°è¸¦ º¸¿©ÁØ´Ù. ±× °úÁ¤Àº ´ÙÀ½°ú °°´Ù:

  1. Ŭ¶óÀÌ¾ðÆ®´Â HTTP GET ¿äûÀ» Àü¼ÛÇÑ´Ù.
  2. Ŭ¶óÀ̾ðÆ®ÀÇ ¿äû µ¥ÀÌŸ°¡ ¼­¹ö¿¡ µµÂøÇÏ¿´À»¶§ Initiation Dispatcher´Â HTTP Çڵ鷯¿¡°Ô ±× »ç½ÇÀ» ¾Ë·ÁÁØ´Ù.
  3. ¿äû µ¥ÀÌŸ°¡ ºñºí·Ï»óÅ·ΠÀÐÇôÁø´Ù. (À̰ÍÀº Àбâ¸í·ÉÀÌ Áï½Ã ¼öÇàÀ» ³¡³»Áö ¸øÇßÀ» °æ¿ì EWOULDBLOCKÀ» ¹ÝȯÇÏ´Â »óŸ¦ ¸»ÇÑ´Ù.) HTTP ¿äûµ¥ÀÌŸ°¡ ¿ÏÀüÈ÷ ÀÐÇôÁú¶§±îÁö 2¹ø°ú 3¹ø´Ü°è¸¦ ¹Ýº¹ÇÑ´Ù.
  4. HTTP Çڵ鷯´Â HTTP ¿äûÀ» ÆÄ½ÌÇÑ´Ù.
  5. ¿äûµÈ È­ÀÏÀ» µ¿±âÀûÀ¸·Î È­ÀÏ ½Ã½ºÅÛÀ¸·Î ºÎÅÍ Àд´Ù.
  6. HTTP Çڵ鷯´Â µ¥ÀÌŸ¸¦ º¸³»±âÀ§ÇØ Initiation Dispatcher¿¡ ¿¬°áÁ¤º¸¸¦ µî·ÏÇÑ´Ù. (´Ù½Ã ¸»Çϸé, Á¢¼Ó»óŰ¡ ¾²±â´ë±â»óÅ·ΠµÈ´Ù.)
  7. Initiation Dispatcher´Â TCP Á¢¼ÓÀÌ ¾²±â¸ðµå »óŶó´Â °ÍÀ» HTTP Çڵ鷯¿¡°Ô ¾Ë·ÁÁØ´Ù.
  8. ¿äû µ¥ÀÌŸ°¡ Ŭ¶óÀÌ¾ðÆ®¿¡°Ô ºñºí·Ï»óÅ·ΠÀü¼ÛµÇ¾îÁø´Ù. (À̰ÍÀº ¾²±â¸í·ÉÀÌ Áï½Ã ¼öÇàÀ» ³¡³»Áö ¸øÇßÀ» °æ¿ì EWOULDBLOCKÀ» ¹ÝȯÇÏ´Â »óŸ¦ ¸»ÇÑ´Ù.) HTTP ¿äûµ¥ÀÌŸ°¡ ¿ÏÀüÈ÷ Àü¼ÛµÇ¾îÁú¶§±îÁö 7¹ø°ú 8¹ø´Ü°è¸¦ ¹Ýº¹ÇÑ´Ù.

reactive À̺¥Æ® µð½ºÆäĪ ¸ðµ¨ÀÌ Àû¿ëµÈ À¥¼­¹ö¿¡ ´ëÇÑ C++ ÄÚµå ¿¹Á¦°¡ ºÎ·Ï A.2¿¡ ÷ºÎµÇ¾îÀÖ´Ù. Initiation Dispatcher°¡ º°µµÀÇ ´ÜÀÏ ¾²·¹µå »ó¿¡¼­ ½ÇÇàµÇ°í Àֱ⠱î´ß¿¡ ³×Æ®¿öÅ© ÀÔÃâ·Â ¸í·ÉµéÀÌ ºí·Ï´çÇÏÁö ¾Ê´Â »óÅ·ΠreactorÀÇ Á¦¾î ¾Æ·¡¿¡¼­ ½ÇÇàµÈ´Ù. If forward progress is stalled on the current operation, the operation is handed off to the Initiation Dispatcher, which monitors the status of the system operation. ¸í·ÉÀÌ ´Ù½Ã ¿ì¼± 󸮵Ǵ »óȲÀÌ ¿À¸é, ¾Ë¸ÂÀº À̺¥Æ® Çڵ鷯¿¡°Ô ÀÌ »ç½ÇÀÌ ¾Ë·ÁÁö°Ô µÈ´Ù.

reactive ¸ðµ¨ÀÇ ÁÖµÈ ÀåÁ¡Àº À̽ļº, coarse-grained µ¿½Ãó¸® Á¦¾î¿¡ µû¸¥ ³·Àº °úºÎÇÏ (´Ù½Ã¸»Çϸé, ½Ì±Û½º·¹µå ¹æ½ÄÀº µ¿±âÈ­³ª ÄÁÅØ½ºÆ® ½ºÀ§ÄªÀÌ ¿ä±¸µÇÁö ¾Ê´Â´Ù.), µð½ºÆäĪ ü°è·Î ºÎÅÍ ¾îÇø®ÄÉÀÌ¼Ç ·ÎÁ÷À» ºÐ¸®ÇÔÀ¸·Î¼­ ¾òÀ»¼ö ÀÖ´Â ¸ðµâÈ­ÀÇ ÀÕÁ¡µéÀ» µé ¼ö ÀÖ´Ù. ±×·³¿¡µµ ºÒ±¸Çϰí, ÀÌ ¹æ½ÄÀº ´ÙÀ½°ú °°Àº ´ÜÁ¡µéÀ» °¡Áö°í ÀÖ´Ù:

  • ÇÁ·Î±×·¥ º¹ÀâµµÀÇ Áõ°¡ : ¾Õ¿¡¼­ ¾ð±ÞÇßµíÀÌ, ¼­¹ö°¡ ƯÁ¤ Ŭ¶óÀÌ¾ðÆ®¿¡ ´ëÇØ ºí·Ï´çÇÏÁö ¾Ê°í ¼­ºñ½º¸¦ ½ÇÇàÇÏ·Á¸é ÇÁ·Î±×·¡¸Ó´Â º¹ÀâÇÑ ·ÎÁ÷À» ÀÛ¼ºÇؾ߸¸ ÇÑ´Ù.
  • ¸ÖƼ¾²·¹µù¿¡ ´ëÇÑ ¿î¿µÃ¼°è Áö¿øÀÇ ºÎÁ· : ´ëºÎºÐÀÇ ¿î¿µÃ¼°èµéÀº reactive µð½ºÆäĪ ¸ðµ¨À» select() ÇÔ¼ö·Î ±¸ÇöÇÑ´Ù[7]. ¾î·°Å³ª, select()´Â °°Àº descriptor set¿¡¼­ ÇѰ³ÀÌ»óÀÇ ¾²·¹µåÀÇ »ç¿ëÀ» Çã¿ëÇÏÁö ¾Ê´Â´Ù. À̰ÍÀº reactive ¸ðµ¨ÀÌ °í¼º´ÉÀÇ ¼­¹öÀÇ Á¦ÀÛ¿¡´Â ¸ÂÁö ¾Ê´Ù´Â Àǹ̰¡ µÈ´Ù. (Çϵå¿þ¾î º´·Ä󸮸¦ È¿À²ÀûÀ¸·Î ÀÌ¿ëÇÏ·Á¸é ¸ÖƼ¾²·¹µåÀÇ »ç¿ëÀº ÇʼöÀûÀ̱⠶§¹®ÀÌ´Ù.)
  • ½ÇÇà°¡´ÉÇÑ taskµéÀÇ ½ºÄÉÁÙ¸µ: ¼±Á¡Çü ¾²·¹µå¸¦ Áö¿øÇÏ´Â µ¿±â¹æ½ÄÀÇ ¸ÖƼ¾²·¹µù ±¸Á¶ÇÏ¿¡¼­´Â, ¼³Ä¡µÈ CPU¸¦ °¡Áö°í ½ÇÇà°¡´ÉÇÑ ¾²·¹µåµéÀ» ½ºÄÉÁÙÇÏ°í ½ÃºÐÇÒÇÏ¿© Á¦¾îÇÏ´Â °ÍÀº ¿î¿µÃ¼°èÀÇ ¿ªÇÒÀ̶ó°í ÇÒ ¼ö ÀÖ´Ù. ÀÌ ½ºÄÉÁÙ¸µÀº ¾îÇø®ÄÉÀ̼ǿ¡¼­ ÇѰ³ÀÇ ¾²·¹µå¸¸ÀÌ Á¸ÀçÇÏ´Â reactive ±¸Á¶¿¡¼­´Â »ç¿ëµÉ ¼ö ¾ø´Ù. ±×·¯¹Ç·Î, ½Ã½ºÅÛ °³¹ßÀÚ´Â À¥¼­¹ö¿¡ ¿¬°áµÈ ¸ðµç Ŭ¶óÀÌ¾ðÆ®µéÀÇ ¿äûÀ» ó¸®Çϴµ¥ À־ ÀÌ 1°³ÀÇ ¾²·¹µåÀÇ ½ÇÇà´ÜÀ§¸¦ ÁÖÀDZí°Ô ½ÃºÐÇÒÇÒ Çʿ䰡 ÀÖ´Ù. À̰ÍÀº ªÀº ÁÖ±â·Î ºñºí·Ï ¸í·ÉµéÀ» ½ÇÇàÇÔÀ¸·Î¼­ ±¸ÇöµÉ ¼ö ÀÖ´Ù.

¿ä¾àÇϸé, ÀÌ·± ´ÜÁ¡µé ¶§¹®¿¡ reactive ¸ðµ¨Àº Çϵå¿þ¾î º´·Ä󸮰¡ Áö¿øµÈ´Ù¸é ±×·¸°Ô ³ôÀº È¿À²À» ±â´ëÇÒ ¼ö ÀÖ´Â ¸ðµ¨ÀÌ ¾Æ´Ï´Ù. ÀÌ ¸ðµ¨Àº ¶ÇÇÑ ¼­¹ö¸¦ ÄÚµùÇÏ´Â µ¥ À־ ÈçÈ÷ ¿ä±¸µÇ´Â ÀÔÃâ·ÂÀÇ ºí·ÏÅ· ȸÇǸ¦ ±¸ÇöÇÏ·Á¸é ´Ù¼Ò ³ôÀº ¼öÁØÀÇ ÇÁ·Î±×·¡¹Ö º¹Àâµµ¸¦ ±Øº¹Çؾ߸¸ ÇÑ´Ù.

3.3 ÇØ°áÃ¥ : proactive 󸮸¦ ÅëÇÑ µ¿½Ãó¸® #

OS Ç÷¿ÆûÀÌ ºñµ¿±â ¸í·ÉµéÀ» Áö¿øÇÒ °æ¿ì, °í¼º´ÉÀÇ À¥¼­¹ö¸¦ ±¸ÇöÇÏ´Â È¿À²ÀûÀÌ°í Æí¸®ÇÑ ¹æ¹ýÀº proactive À̺¥Æ® µð½ºÆäĪÀ» »ç¿ëÇÏ´Â °ÍÀÌ´Ù. proactive À̺¥Æ® µð½ºÆäĪÀ» »ç¿ëÇÏ¿©µðÀÚÀÎµÈ À¥ ¼­¹ö´Â ÇѰ³ÀÌ»óÀÇ ¾²·¹µå¸¦ Á¦¾îÇÏ¿© ºñµ¿±â¸í·ÉÀÇ ¿Ï·á¿©ºÎ¸¦ ´Ù·ç´Â °ÍÀÌ °¡´ÉÇÏ´Ù. µû¶ó¼­, proactor ÆÐÅÏÀº ¿Ï·á À̺¥Æ® µð¸ÖƼÇ÷º½Ì°ú À̺¥Æ® Çڵ鷯 µð½ºÆäĪÀ» ÅëÇÕÇÔÀ¸·Î½á ºñµ¿±â¹æ½ÄÀÇ À¥¼­¹ö ±¸Á¶¸¦ ´Ü¼øÈ­½ÃŲ´Ù.

ºñµ¿±â À¥¼­¹ö´Â ¿î¿µÃ¼°è¿¡ óÀ½¿¡ ºñµ¿±â¸í·ÉÀ» ½Ãµ¿ÇÒ ¶§¿Í ¸í·ÉÀÌ ¿Ï·áÇßÀ» ¶§¸¦ ¾Ë·ÁÁÖ±â À§ÇÑ ¿Ï·á ¹ß¼ÛÀÚ(completion dispatcher)¿¡ ÄݹéÇÔ¼ö¸¦ µî·ÏÇϱâ À§ÇØ proactor ÆÐÅÏÀ» »ç¿ëÇÒ ¼ö ÀÖ´Ù. ¿î¿µÃ¼°è´Â À̶§ À¥¼­¹öÀÔÀå¿¡¼­ ¸í·ÉÀ» ¼öÇàÇÏ¸ç ¼øÂ÷ÀûÀ¸·Î ¿î¿µÃ¼°è ³»ÀÇ Àß ¾Ë·ÁÁø °÷¿¡ °á°ú¸¦ ÀûÀç(queue)ÇÑ´Ù. ¿Ï·á ¹ß¼ÛÀÚ(Completion Dispatcher)´Â ¿Ï·á ¾Ë¸²¸Þ¼¼ÁöµéÀ» »Ì¾Æ³»°í(dequeue), ¾îÇø®ÄÉÀÌ¼Ç µ¿ÀÛÀ§ÁÖÀÇ À¥¼­¹ö Äڵ带 ´ãÀº ¾Ë¸ÂÀº ÄݹéÇÔ¼ö¸¦ ½ÇÇàÇÏ´Â ¿ªÇÒÀ» ´ã´çÇÑ´Ù.

±×¸² 5¿Í 6Àº proactor ÆÐÅϹæ½ÄÀÇ À̺¥Æ® µð½ºÆÐĪÀ» »ç¿ëÇÏ¿© µðÀÚÀÎµÈ À¥¼­¹ö°¡ ÇѰ³ ÀÌ»óÀÇ ¾²·¹µå³»¿¡¼­ ¿©·¯ Ŭ¶óÀÌ¾ðÆ®µéÀ» ¾î¶»°Ô µ¿½Ãó¸®ÇÏ´ÂÁö¸¦ º¸¿©ÁØ´Ù.

proactor_figure_5.png

±×¸² 5´Â Ŭ¶óÀÌ¾ðÆ®°¡ À¥¼­¹ö·Î Á¢¼ÓÇßÀ»¶§ ½ÇÇàµÇ´Â ´Ü°èÀÇ ¼ø¼­¸¦ º¸¿©ÁØ´Ù.

  1. À¥¼­¹ö´Â acceptor¿¡°Ô ºñµ¿±â accept 󸮸¦ ÃʱâÈ­Çϵµ·Ï ¾Ë·ÁÁØ´Ù.
  2. acceptor´Â ¿î¿µÃ¼°èÀÇ ±â´ÉÀ» ÀÌ¿ëÇÏ¿© ºñµ¿±â accept ¿äûÀ» ÃʱâÈ­Çϰí, ±× ÀÚ½ÅÀ» ¿Ï·á Çڵ鷯(Completion Handler)¿Í ¿Ï·á ¹ß¼ÛÀÚ(Completion Dispatcher)ÀÇ ÂüÁ¶·Î½á ³Ñ±â°Ô µÈ´Ù. (À̰ÍÀº ºñµ¿±â acceptÀÇ ¿Ï·á¿©ºÎ¸¦ acceptor¿¡°Ô ¾Ë·ÁÁִµ¥ »ç¿ëµÈ´Ù.)
  3. À¥¼­¹ö´Â ¿Ï·á ¹ß¼ÛÀÚÀÇ À̺¥Æ® ·çÇÁ¸¦ ½ÇÇàÇÑ´Ù.
  4. Ŭ¶óÀÌ¾ðÆ®°¡ À¥¼­¹ö¿¡ Á¢¼ÓÇÑ´Ù.
  5. ºñµ¿±â accept ¸í·ÉÀÌ ¿Ï·áÇϸé, ¿î¿µÃ¼°è´Â ¿Ï·á ¹ß¼ÛÀÚ¿¡°Ô ÅëÁöÇÑ´Ù.
  6. ¿Ï·á ¹ß¼ÛÀÚ´Â acceptor¿¡°Ô ÅëÁöÇÑ´Ù.
  7. acceptor´Â HTTP Çڵ鷯¸¦ »ý¼ºÇÑ´Ù.
  8. HTTP Çڵ鷯´Â Ŭ¶óÀÌ¾ðÆ®·Î ºÎÅÍ Àü¼ÛµÇ´Â ¿äû µ¥ÀÌŸ¸¦ ºñµ¿±âÀûÀ¸·Î Àд ÀÛ¾÷À» ÃʱâÈ­ÇÏ°í ±× ÀÚ½ÅÀ» ¿Ï·á Çڵ鷯(Completion Handler)¿Í ¿Ï·á ¹ß¼ÛÀÚ(Completion Dispatcher)ÀÇ ÂüÁ¶·Î½á ³Ñ±â°Ô µÈ´Ù. (À̰ÍÀº ºñµ¿±â ÀбâÀÛ¾÷ÀÇ ¿Ï·á¿©ºÎ¸¦ acceptor¿¡°Ô ¾Ë·ÁÁִµ¥ »ç¿ëµÈ´Ù.)

proactor_figure_6.png

±×¸² 6Àº proactor ÆÐÅÏÀ» Àû¿ëÇÑ À¥¼­¹ö°¡ HTTP GET ¿äûÀ» ¼­ºñ½ºÇϱâÀ§ÇÑ ´Ü°è¸¦ º¸¿©ÁØ´Ù. ÀÌ ´Ü°è´Â ¾Æ·¡¿Í °°´Ù.
  1. Ŭ¶óÀÌ¾ðÆ®°¡ HTTP GET ¿äûÀ» Àü¼ÛÇÑ´Ù.
  2. Àбâ ÀÛ¾÷ÀÌ ¿Ï·áµÇ¸é ¿î¿µÃ¼°è´Â ¿Ï·á ¹ß¼ÛÀÚ¿¡°Ô ÅëÁöÇÑ´Ù.
  3. ¿Ï·á ¹ß¼ÛÀÚ´Â HTTP Çڵ鷯¿¡°Ô ÅëÁöÇÑ´Ù. (2´Ü°è¿Í 3´Ü°è´Â Àüü ¿äû ¸Þ¼¼Áö°¡ ¸ðµÎ Àü¼Û¹Þ¾ÆÁú ¶§±îÁö ¹Ýº¹ÇÏ°Ô µÈ´Ù.)
  4. HTTP Çڵ鷯´Â ¿äû µ¥ÀÌŸ¸¦ ÆÄ½ÌÇÑ´Ù.
  5. HTTP Çڵ鷯°¡ µ¿±âÀûÀ¸·Î ¿äûµÈ È­ÀÏÀ» ÀоîµéÀδÙ.
  6. HTTP Çڵ鷯´Â È­ÀÏ µ¥ÀÌŸ¸¦ Á¢¼ÓµÈ Ŭ¶óÀÌ¾ðÆ®·Î Àü¼ÛÇϱâÀ§ÇÑ ºñµ¿±â ¸í·ÉÀ» ÃʱâÈ­ÇÑ´Ù. ±×¸®°í ±× ÀÚ½ÅÀ» ¿Ï·á Çڵ鷯(Completion Handler)¿Í ¿Ï·á ¹ß¼ÛÀÚ(Completion Dispatcher)ÀÇ ÂüÁ¶·Î½á ³Ñ±â°Ô µÈ´Ù. À̰ÍÀº ºñµ¿±â È­ÀÏÀü¼ÛÀÛ¾÷ÀÇ ¿Ï·á¿©ºÎ¸¦ HTTP Çڵ鷯¿¡°Ô ÅëÁöÇϴµ¥ »ç¿ëµÈ´Ù.
  7. Àü¼ÛÀÛ¾÷ÀÌ ¿Ï·áµÇ¸é ¿î¿µÃ¼°è´Â ¿Ï·á ¹ß¼ÛÀÚ¿¡°Ô ÅëÁöÇÑ´Ù.
  8. À̶§ ¿Ï·á ¹ß¼ÛÀÚ´Â ¿Ï·á Çڵ鷯¿¡°Ô ÅëÁöÇÑ´Ù. (6~8´Ü°è´Â È­ÀÏÀÌ ¸ðµÎ Àü¼ÛµÉ¶§±îÁö ¹Ýº¹µÈ´Ù.)

À¥¼­¹ö¿¡ proactor À̺¥Æ® µð½ºÆäĪ ¸ðµ¨À» Àû¿ëÇÑ C++ Äڵ忹Á¦°¡ 8Àå¿¡ ¼Ò°³µÇ¾îÀÖ´Ù. proactor ÆÐÅÏÀ» Àû¿ëÇßÀ» ¶§ °¡Àå Å« ÀÕÁ¡Àº ´ÙÁßÀ¸·Î ½ÇÇàµÇ´Â µ¿½Ãó¸® ¸í·ÉµéÀ» ²À ¿©·¯°³ÀÇ ¾²·¹µå¸¦ ÇÊ¿ä·Î ÇÏÁö¾ÊÀ¸¸é¼­ º´·ÄÀûÀ¸·Î ½Ãµ¿ÇÏ°í ½ÇÇàÇÒ ¼ö ÀÖ´Ù´Â Á¡ÀÌ´Ù. °¢ ¸í·ÉµéÀº ºñµ¿±âÀûÀ¸·Î ¾îÇø®ÄÉÀ̼ǿ¡ ÀÇÇØ ½Ãµ¿µÇ¸ç, ¿î¿µÃ¼°èÀÇ ÀÔÃâ·Â ºÎ¼Ó½Ã½ºÅÛ³»¿¡¼­ ¿Ï·áµÉ ¶§ ±îÁö ½ÇÇàÀ» °è¼ÓÇÑ´Ù. ÀÌÁ¦ ¸í·ÉµéÀ» ÃʱâÈ­ÇÏ´Â ¾²·¹µå´Â ÇѰ¡Áö ÀÛ¾÷¸¸À» Àü´ãÇÏÁö ¾Ê°í Ãß°¡µÈ ¿äûµéÀ» ¼­ºñ½ºÇØÁÖ´Â °ÍÀÌ °¡´ÉÇÏ´Ù. ¿¹¸¦ µéÀÚ¸é, ¾ÕÀÇ ¿¹Á¦¿¡¼­ ¿Ï·á ¹ß¼ÛÀÚ´Â ´ÜÀÏ ¾²·¹µå ¹æ½ÄÀÌ µÉ ¼ö ÀÖ´Â °ÍÀÌ´Ù. HTTP ¿äûÀÌ ¼­¹ö¿¡ µµÂøÇϸé, ´ÜÀÏ ¿Ï·á¹ß¼ÛÀÚ ¾²·¹µå´Â ¿äû ¸Þ¼¼Áö¸¦ ÆÄ½ÌÇϰí, È­ÀÏÀ» Àаí, Ŭ¶óÀÌ¾ðÆ®¿¡°Ô ¿äû¿¡ ´ëÇÑ ÀÀ´äÀ» Àü¼ÛÇÑ´Ù. ÀÀ´äÀÌ ºñµ¿±âÀûÀ¸·Î º¸³»¾îÁö±â ¶§¹®¿¡, ´Ù¼öÀÇ ÀÀ´äÀ» µ¿½Ã¿¡ ºÎºÐÀûÀ¸·Î ó¸®ÇÒ ¼ö ÀÖ°Ô µÇ´Â °ÍÀÌ´Ù. °Ô´Ù°¡, µ¿±âÀû È­ÀÏÀбâ ÀÛ¾÷Àº ºñµ¿±â È­ÀÏÀбâ ÀÛ¾÷À¸·Î ±³Ã¼ÇÒ ¼öµµ ÀÖÀ» °ÍÀÌ´Ù. (ÀÌ·¯¸é µ¿½Ãó¸®µÉ °¡´É¼ºÀÌ ´õ ³ô¾ÆÁö°ÔµÈ´Ù.) ¸¸¾à È­ÀÏÀбâÀÛ¾÷ÀÌ ºñµ¿±âÀûÀ¸·Î ¼öÇàµÈ´Ù¸é, HTTP Çڵ鷯¿¡ ÀÇÇØ 󸮵Ǵ ´Ü ÇϳªÀÇ µ¿±âÀû ÀÛ¾÷Àº HTTP ÇÁ·ÎÅäÄÝ ÆÄ½Ì¹Û¿¡ ¾ø°Ô µÈ´Ù.

proactor ¸ðµ¨ÀÇ ÁÖ¿ä ´ÜÁ¡Àº reactor ¸ðµ¨º¸´Ù ÇÁ·Î±×·¡¹Ö ·ÎÁ÷ÀÌ º¸´Ù ´õ º¹ÀâÇØÁú ¼ö ÀÖ´Ù´Â °Í ÀÌ´Ù. °Ô´Ù°¡, ºñµ¿±â ¸í·ÉµéÀº °¡²û ¿¹ÃøÇϱâ Èûµé°í ¹Ýº¹µÇÁö¾Ê´Â ½ÇÇà¼ø¼­¸¦ °¡Áö´Â ±î´ß¿¡ proactor ÆÐÅÏÀº ½ÇÇà ºÐ¼®°ú µð¹ö±×ÇϱⰡ ´Ù¼Ò ¾î·Æ´Ù. 7ÀåÀº ºñµ¿±â ¾îÇø®ÄÉÀ̼ÇÀ» ´Ü¼øÈ­½ÃÄÑÁÖ´Â (ºñµ¿±â ¿Ï·á ÅäÅ«[8]°ú °°Àº) ´Ù¸¥ ÆÐÅϵéÀ» Àû¿ë½ÃŰ´Â ¹æ¹ý¿¡ ´ëÇØ ¼³¸íÇϰí ÀÖ´Ù.

4 Àû¿ëÇØ¾ß ÇÒ °æ¿ì #

proactor ÆÐÅÏÀº ´ÙÀ½°ú °°Àº Á¶°ÇÀ» ÇѰ³ ÀÌ»ó ¸¸Á·ÇÒ ¶§ »ç¿ëÇϱ⸦ ±ÇÀåÇÑ´Ù.
  • È£ÃâµÇ´Â ¾²·¹µå¸¦ ºí·ÏÇÏÁö ¾Ê°í ÇѰ³ ÀÌ»óÀÇ ºñµ¿±â ¸í·ÉµéÀ» ½ÇÇàÇÒ Çʿ䰡 ÀÖÀ» ¶§.
  • ºñµ¿±â ¸í·ÉµéÀÌ ¿Ï·áµÉ ¶§¸¦ ÅëÁö¹Þ¾Æ¾ß ÇÒ ¶§.
  • ÀÔÃâ·Â ¸ðµ¨¿¡ µ¶¸³ÀûÀ¸·Î ´Ù¾çÇÑ µ¿½Ãó¸® Àü·«ÀÌ ¿ä±¸µÉ ¶§.
  • ¾îÇø®ÄÉÀÌ¼Ç µ¶¸³ÀûÀ¸·Î ±¸ÇöµÈ ÇϺα¸Á¶·ÎºÎÅÍ ¾îÇø®ÄÉÀÌ¼Ç ÀÇÁ¸ÀûÀÎ ·ÎÁ÷À» Èí¼öÇÒ °æ¿ì ÀÕÁ¡ÀÌ ¸¹À» ¶§.
  • ¸ÖƼ¾²·¹µù ¹æ½Ä ȤÀº reactor µð½ºÆÐĪ ¹æ½ÄÀ¸·Î´Â ¼º´ÉÀÌ ±â´ëÇÑ °Íº¸´Ù ³·°Å³ª ºñÈ¿À²ÀûÀÎ °æ¿ì.

5 ±¸Á¶¿Í ±¸¼º¿ä¼Òµé #

proactor ÆÐÅÏÀÇ ±¸Á¶´Â figure 7¿¡ OMT Ç¥±â¹ýÀ¸·Î ±×·ÁÁ®ÀÖ´Ù.

proactor_figure_7.png

proactor ÆÐÅÏÀÇ ÇÙ½É ±¸¼º¿ä¼Ò´Â ´ÙÀ½°ú °°´Ù:
  • Proactive Initiator (À¥¼­¹ö ¾îÇø®ÄÉÀ̼ÇÀÇ ÁÖ ¾²·¹µå) : A Proactive Initiator is any entity in the application that initiates an Asynchronous Operation. The Proactive Initiator registers a Completion Handler and a Completion Dispatcher with a Asynchronous Operation Processor, which notifies it when the operation completes.
  • ¿Ï·á(Completion) Çڵ鷯 (the Acceptor and HTTP Handler): The Proactor pattern uses Completion Handler interfaces that are implemented by the application for Asynchronous Operation completion notification.
  • ºñµ¿±â ¸í·É (the methods Async Read, Async Write, and Async Accept) : Asynchronous Operations are used to execute requests (such as I/O and timer operations) on behalf of applications. When applications invoke Asynchronous Operations, the operations are performed without borrowing the application's thread of control. Therefore, from the application¡¯s perspective, the operations are performed asynchronously. When Asynchronous Operations complete, the Asynchronous Operation Processor delegates application notifications to a Completion Dispatcher.
In contrast, the reactive event dispatching model [5] steals the applica-tion¡¯s thread of control to perform the operation synchronously.
  • ºñµ¿±â ¸í·É ÇÁ·Î¼¼¼­ (the Operating System) : Asynchronous Operations are run to completion by the Asynchronous Operation Processor. This component is typically implemented by the OS.
  • ¿Ï·á(Completion) µð½ºÆÐÃÄ (the Notification Queue) : The Completion Dispatcher is responsible for calling back to the application's Completion Handlers when Asynchronous Operations complete. When the Asynchronous Operation
Processor completes an asynchronously initiated operation, the Completion Dispatcher performs an application callback on its behalf.

6 Collaborations #


proactor_figure_8.png

There are several well-defined steps that occur for all Asynchronous Operations. At a high level of abstraction, applications initiate operations asynchronously and are notified when the operations complete. Figure 8 shows the following interactions that must occur between the pattern participants:

  1. Proactive Initiators initiates operation: To perform asynchronous operations, the application initiates the operation on the Asynchronous Operation Processor. For instance, a Web server might ask the OS to transmit a file over the network using a particular socket connection. To request such an operation, the Web server must specify which file and network connection to use. Moreover, the Web server must specify (1) which Completion Handler to notify when the operation completes and (2) which Completion Dispatcher should perform the callback once the file is transmitted.
  2. Asynchronous Operation Processor performs operation: When the application invokes operations on the Asynchronous Operation Processor it runs them asynchronously with respect to other application operations. Modern operating systems (such as Solaris and Windows NT) provide asynchronous I/O subsystems within the kernel.
  3. The Asynchronous Operation Processor notifies the Completion Dispatcher: When operations complete, the Asynchronous Operation Processor retrieves the Completion Handler and Completion Dispatcher that were specified when the operation was initiated. The Asynchronous Operation Processor then passes the Completion Dispatcher the result of the Asynchronous Operation and the Completion Handler to call back. For instance, if a file was transmitted asynchronously, the Asynchronous Operation Processor may report the completion status (such as success or failure), as well as the number of bytes written to the network connection.
  4. Completion Dispatcher notifies the application: The Completion Dispatcher calls the completion hook on the Completion Handler, passing it any completion data specified by the application. For instance, if an asynchronous read completes, the Completion Handler will typically be passed a pointer to the newly arrived data.

7 °á·Ð #

ÀÌ ÀåÀº Proactor ÆÐÅÏÀÇ Àå´ÜÁ¡À» ¼³¸íÇÑ´Ù.

7.1 ÀåÁ¡ #

proactor ÆÐÅÏÀº ´ÙÀ½°ú °°Àº ÀåÁ¡µéÀ» °¡Áö°í ÀÖ´Ù:
  1. °í·Á»çÇ׿¡ ´ëÇÑ ±¸ºÐÀÌ º¸´Ù´õ ¸íÈ®ÇÔ: Proactor ÆÐÅÏÀº ¾îÇø®ÄÉÀ̼ǰú´Â µ¶¸³ÀûÀÎ ºñµ¿±â ü°èµéÀ» ¾îÇø®ÄÉÀÌ¼Ç °íÀ¯ÀÇ ±â´É°ú ºÐ¸®½ÃÄÑÁØ´Ù. The application-independent mechanisms become reusable components that know how to demultiplex the completion events associated with Asynchronous Operations and dispatch the appropriate callback methods defined by the Completion Handlers. Likewise, the application-specific functionality knows how to perform a particular type of service (such as HTTP processing).
  2. ¾îÇø®ÄÉÀÌ¼Ç ·ÎÁ÷¿¡ ´ëÇÑ À̽ļº Áõ°¡: It improves application portability by allowing its interface to be reused independently of the underlying OS calls that perform event demultiplexing. These system calls detect and report the events that may occur simultaneously on multiple event sources. Event sources may include I/O ports, timers, synchronization objects, signals, etc. On real-time POSIX platforms, the asynchronous I/O functions are provided by the aio family of APIs [9]. In Windows NT, I/O completion ports and overlapped I/O are used to implement asynchronous I/O 10.
  3. ¿Ï·á µð½ºÆäÃİ¡ µ¿½Ãó¸® ü°è¸¦ ÀºÆó(encapsulate)½ÃÄÑÁØ´Ù: A benefit of decoupling the Completion Dispatcher from the Asynchronous Operation Processor is that applications can configure Completion Dispatchers with various concurrency strategies without affecting other participants. As discussed in Section 7, the Completion Dispatcher can be configured to use several concurrency strategies including single-threaded and Thread Pool solutions.
  4. ¾²·¹µù Á¤Ã¥ÀÌ µ¿½Ãó¸® Á¤Ã¥°ú Áߺ¹µÇÁö ¾Ê´Â´Ù.: Since the Asynchronous Operation Processor completes potentially long-running operations on behalf of Proactive Initiators, applications are not forced to spawn threads to increase concurrency. This allows an application to vary its concurrency policy independently of its threading policy. For instance, a Web server may only want to have one thread per CPU, but may want to service a higher number of clients simultaneously.
  5. È¿À²ÀÇ Áõ°¡: Multithreaded operating systems perform context switches to cycle through multiple threads of control. While the time to perform a context switch remains fairly constant, the total time to cycle through a large number of threads can degrade application performance significantly if the OS context switches to an idle thread. For instance, threads may poll the OS for completion status, which is inefficient. The Proactor pattern can avoid the cost of context switching by activating only those logical threads of control that have events to process. For instance, a Web server does not need to activate an HTTP Handler if there is no pending GET request.
  6. ¾îÇø®ÄÉÀÌ¼Ç µ¿±âÈ­ÀÇ ´Ü¼øÈ­: As long as Completion Handlers do not spawn additional threads of control, application logic can be written with little
or no regard to synchronization issues. Completion Handlers can be written as if they existed in a conventional single-threaded environment. For instance, a Web server's HTTP GET Handler can access the disk through an Async Read operation (such as the Windows NT TransmitFile function [1]).

7.2 ´ÜÁ¡ #

proactor ÆÐÅÏÀº ´ÙÀ½°ú °°Àº ´ÜÁ¡µéÀ» °¡Áö°í ÀÖ´Ù:
  1. µð¹ö±×ÇÏ±â ¾î·Æ´Ù : proactor ÆÐÅÏÀ» »ç¿ëÇÏ¿© °³¹ßµÈ ¾îÇø®ÄÉÀ̼ÇÀº µð¹ö±×ÇϱⰡ ¾î·Á¿öÁú ¼ö ÀÖ´Ù. (À̰ÍÀº µÚÁý¾îÁø Á¦¾î È帧ÀÌ ÇÁ·¹ÀÓ¿öÅ© ÇϺα¸Á¶¿Í ¾îÇø®ÄÉÀ̼ǿ¡¼­ Á¤ÀÇµÈ Çڵ鷯»óÀÇ Äݹé»çÀ̸¦ ¿Ô´Ù°¬´ÙÇϱ⠶§¹®ÀÌ´Ù. ÇѸ¶µð·Î ÃßÀûÇÏ´Ùº¸¸é ³»°¡ ¾îµðÀÖÁö? ÇÏ´Â ºÎºÐÀ» ¸»ÇÑ´Ù.) ÀÌ ¶§¹®¿¡ ÇÁ·¹ÀÓ¿öÅ©ÀÇ ½ÇÇà°úÁ¤ Áß¿¡ "ÇÑÁÙÇÑÁÙ¾¿ ¹â¾Æ³ª°¡´Â ¹æ½Ä"ÀÇ µð¹ö±×´Â Á¤¸»·Î ¾î·Á¿öÁú ¼ö ÀÖ´Ù. (¾îÇø®ÄÉÀÌ¼Ç °³¹ßÀÚµéÀº ÇÁ·¹ÀÓ¿öÅ©ÀÇ ¼Ò½º Äڵ带 °¡Áö°í ÀÖÁö ¾Ê°Å³ª ÀÌÇØÇÏÁö ¸øÇϱ⠶§¹®ÀÌ´Ù) À̰ÍÀº LEX³ª YACCÀ¸·Î ¾²¿©Áø ÄÄÆÄÀÏ·¯ÀÇ ±¸¹® ºÐ¼®±â³ª ÆÄ¼­¸¦ µð¹ö±×ÇÒ ¶§ ºÎµóÈ÷´Â ¹®Á¦¿Í ºñ½ÁÇÏ´Ù. ÀÌ·± ÇüÅÂÀÇ ¾îÇø®ÄÉÀ̼ǿ¡¼­´Â, Á¦¾îµÇ´Â ¾²·¹µå°¡ »ç¿ëÀÚ Á¤ÀÇµÈ ¾×¼Ç ·çƾ»ó¿¡ ÀÖÀ»¶§ µð¹ö±ëÀº ¼ö¿ùÇØÁú ¼ö ÀÖ´Ù. (In these applications, debugging is straightforward when the thread of control is within the user-defined action routines.) Çѹø Á¦¾î ¾²·¹µå°¡ À¯ÇѰáÁ¤¿ÀÅ丶Ÿ(DFA : Deterministic Finite Automata)¸¦ »ý¼ºÇÏ°í ¹ÝȯµÇ¸é, ¾îÂîµÇ¾ú´ø°£¿¡ ÇÁ·Î±×·¥ ·ÎÁ÷À» µû¶ó°¡´Â °ÍÀº Èûµé¾îÁø´Ù.
  2. µÎµå·¯Áø(outstanding) ¸í·Éó¸®¿Í ½ºÄÉÁÙ¸µ : Proactive Initiators´Â ºñµ¿±â ¸í·ÉµéÀÌ ½ÇÇàµÇ´Â ¼ø¼­¸¦ Á¶Á¤ÇÒ ¼ö ¾øÀ» ¼öµµ ÀÖ´Ù. ±×·¯¹Ç·Î, ºñµ¿±â ¸í·É ÇÁ·Î¼¼¼­´Â ºñµ¿±â ¸í·ÉµéÀÇ ¿ì¼±¼øÀ§ÁöÁ¤°ú Ãë¼Ò±â´ÉÀ» Áö¿øÇϵµ·Ï ÁÖÀDZí°Ô Á¦À۵Ǿî¾ß ÇÑ´Ù.

8 ±¸Çö #

Proactor ÆÐÅÏÀº ´Ù¾çÇÑ ¹æ¹ýÀ¸·Î ±¸ÇöµÉ ¼ö ÀÖ´Ù. ÀÌ ÀåÀº Proactor ÆÐÅÏÀ» ±¸ÇöÇϴµ¥ ÇÊ¿äÇÑ ´Ü°è¸¦ ¾Ë¾Æº»´Ù.

8.1 ºñµ¿±â ¸í·É ÇÁ·Î¼¼¼­ÀÇ ±¸Çö #

The first step in implementing the Proactor pattern is build-ing the Asynchronous Operation Processor. The Asynchronous Operation Processor is responsible for executing operations asynchronously on behalf of applications. As a result, its two primary responsibilities are exporting Asynchronous Operation APIs and implementing an Asynchronous Operation Engine to do the work.

8.1.1 ºñµ¿±â ¸í·É API¸¦ Á¤ÀÇÇϱâ #

The Asynchronous Operation Processor must provide an API that allows applications to request Asynchronous Operations. There are several forces to be considered when designing these APIs:

  • À̽ļº: The APIs should not tie an application nor its Proactve Initiators to a particular platform.
  • À¶Å뼺: Often, asynchronous APIs can be shared for many types of operations. For instance, asynchronous I/O operations can often be used to perform I/O on multiple mediums (such as network and files). It may be beneficial to design APIs that support such reuse.
  • Äݹé : The Proactive Initiators must register a callback when the operation is invoked. A common approach to implement callbacks is to have the calling objects (clients) export an interface known by the caller (server). Therefore, Proactive Initiators must inform the Asynchronous Operation Processor which Completion Handler should be called back when an operation completes.
  • ¿Ï·á µð½ºÆÐÃÄ : Since an application may use multiple Completion Dispatchers, the Proactive Initiator also must indicate which Completion Dispatcher should perform the callback.

Given all of these concerns, consider the following API for asynchronous reads and writes. The Asynch Stream class is a factory for initiating asynchronous reads and writes. Once constructed, multiple asynchronous reads and writes can be started using this class. An Asynch Stream::Read Result will be passed back to the handler when the synchronous read completes via the handle read callback on the Completion Handler. Similarly, an Asynch Stream::Write Result will be passed back to the handler when the asynchronous write completes via the handle write callback on Completion Handler.
class Asynch_Stream
   // = TITLE
   // A Factory for initiating reads
   // and writes asynchronously.
{
   // Initializes the factory with information
   // which will be used with each asynchronous
   // call. <handler> is notified when the
   // operation completes. The asynchronous
   // operations are performed on the <handle>
   // and the results of the operations are
   // sent to the <Completion_Dispatcher>.
   Asynch_Stream (Completion_Handler &handler, HANDLE handle, Completion_Dispatcher *);

   // This starts off an asynchronous read.
   // Upto <bytes_to_read> will be read and
   // stored in the <message_block>.
   int read (Message_Block &message_block, u_long bytes_to_read, const void *act = 0);

   // This starts off an asynchronous write.
   // Upto <bytes_to_write> will be written
   // from the <message_block>.
   int write (Message_Block &message_block, u_long bytes_to_write, const void *act = 0);
   ...
};

8.1.2 ºñµ¿±â ó¸® ¿£ÁøÀÇ ±¸Çö #

The Asynchronous Operation Processor must contain a mechanism that performs the operations asynchronously. In other words, when an application thread invokes an Asynchronous Operation, the operation must be performed without borrowing the application's thread of control. Fortunately, modern operating systems provide mechanisms for Asynchronous Operations (for example, POSIX asynchronous I/O and WinNT overlapped I/O). When this is the case, implementing this part of the pattern simply requires mapping the platform APIs to the Asynchronous Operation APIs described above. If the OS platform does not provide support for Asynchronous Operations, there are several implementation techniques that can be used to build an Asynchronous Operation Engine. Perhaps the most intuitive solution is to use dedicated threads to perform the Asynchronous Operations for applications.

To implement a threaded Asynchronous Operation Engine, there are three primary steps:
  1. Operation invocation: Because the operation will be performed in a different thread of control from the invoking application thread, some type of thread synchronization must occur. One approach would be to spawn a thread for each operation. A more common approach is for the Asynchronous Operation Processor to control a pool of dedicated threads. This approach would require that the application thread queue the operation request before continuing with other application computations.
  2. Operation execution: Since the operation will be performed in a dedicated thread, it can perform ¡°blocking¡± operations without directly impeding progress of the application. For instance, when providing a mechanismfor asynchronous I/O reads, the dedicated thread can block while reading from socket or file handles.
  3. Operation completion: When the operation completes, the application must be notified. In particular, the dedicated thread must delegate application-specific notifications to the Completion Dispatcher. This will require additional synchronization between threads.

8.2 Implementing the Completion Dispatcher #

The Completion Dispatcher calls back to the Completion Handler that is associated with the application objects when it receives operation completions from the Asynchronous Operation Processor. There are two issues involved with implementing the Completion Dispatcher: (1) implementing callbacks and (2) defining the concurrency strategy used to perform the callbacks.

8.2.1 Implementing Callbacks #

The Completion Dispatcher must implement a mechanism through which Completion Handlers are invoked. This requires Proactive Initiators to specify a callback when initiating operations. The following are common callback alternatives:
  • Callback class: The Completion Handler exports an interface known by the Completion Dispatcher. The Completion Dispatcher calls back on a method in this interface when the operation completes and passes it information about the completed operation (such as the number of bytes read from the network connection).
  • Function pointer: The Completion Dispatcher invokes the Completion Handler via a callback function pointer. This approach effectively breaks the knowledge dependency between the Completion Dispatcher and the Completion Handler. This has two benefits:
    1. The Completion Handler is not forced to export a specific interface; and
    2. There is no need for compile-time dependencies between the Completion Dispatcher and the Completion Handler.
  • Rendezvous: The Proactive Initiator can establish an event object or a condition variable, which serves as a rendezvous between the Completion Dispatcher and the Completion Handler. This is most common when the Completion Handler is the Proactive Initiator. While the Asynchronous Operation runs to completion, the Completion Handler processes other activity. Periodically, the Completion Handler will check at the rendezvous point for completion status.

8.2.2 Defining Completion Dispatcher Concurrency Strategies #

A Completion Dispatcher will be notified by the Asynchronous Operation Processor when operations completes. At this point, the Completion Dispatcher can utilize one of the following concurrency strategies to perform the application callback:

  • Dynamic-thread dispatching: A thread can be dynamically allocated for each Completion Handler by the Completion Dispatcher. Dynamic-thread dispatching can be implemented with most multi-threaded operating systems. On some platforms, this may be the least efficient technique of those listed for Completion Dispatcher implementations due to the overhead of creating and destroying thread resources.
  • Post-reactive dispatching: An event object or condition variable established by the Proactive Initiator can be signaled by the Completion Dispatcher. Although polling and spawning a child thread that blocks on the event object are options, the most efficient method for Post-reactive dispatching is to register the event with a Reactor. Post-reactive dispatching can be implemented with aio suspend in POSIX real-time environments and with WaitForMultipleObjects in Win32 environ-ments.
  • Call-through dispatching: The thread of control from the Asynchronous Operation Processor can be borrowed by theCompletion Dispatcher to execute the Completion Handler. This ¡°cycle stealing¡± strategy can increase performance by decreasing the incidence of idle threads. In the cases where older operating systems will context switch to idle threads just to switch back out of them, this approach has a great potential of reclaiming ¡°lost¡± time. Call-through dispatching can be implemented in Windows NT using the ReadFileEx and WriteFileEx Win32 functions. For example, a thread of control can use these calls to wait on a semaphore to become signaled. When it waits, the thread informs the OS that it is entering into a special state known as an ¡°alertable wait state.¡± At this point, the OS can seize control of the waiting thread of control's stack and associated resources in order to execute the Completion Handler.
  • Thread Pool dispatching: A pool of threads owned by the Completion Dispatcher can be used for Completion Handler execution. Each thread of control in the pool has been dynamically allocated to an available CPU. Thread pool dispatching can be implemented with Windows NT's I/O Completion Ports. When considering the applicability of the Completion Dispatcher techniques described above, consider the possible combinations of OS environments and physical hardware shown in Table 1.

proactor_table_1.png

If your OS only supports synchronous I/O, then refer to the Reactor pattern [5]. However, most modern operating systems support some form of asynchronous I/O. In combination A and B from Table 1, the Post-reactive approach to asynchronous I/O is probably the best, assuming you are not waiting on any semaphores or mutexes. If you are, a Call-through implementation may be more responsive. In combination C, use a Call-through approach. In combination D, use a Thread Pool approach. In practice, systematic empirical measurements are necessary to select the most appropriate alternative.

8.3 Implementing Completion Handlers #

The implementation of Completion Handlers raises the following concerns.

8.3.1 State Integrity #

A Completion Handler may need to maintain state information concerning a specific request. For instance, the OS may notify the Web Server that only part of a file was written to the network communication port. As a result, a Completion Handler may need to reissue the request until the file is fully written or the connection becomes invalid. Therefore, it must know the file that was originally specified, how many bytes are left to write, and what was the file pointer position at the start of the previous request. There is no implicit limitation that prevents Proactive Initiators from assigning multiple Asynchronous Operation requests to a single Completion Handler. As a result, the Completion Handler must tie request-specific state information throughout the chain of completion notifications. To do this, Completion Handlers can utilize the Asynchronous Completion Token pattern [8].

8.3.2 Resource Management #

As with any multi-threaded environment, the Proactor pattern does not alleviate Completion Handlers from ensuring that access to shared resources is thread-safe. However, a Completion Handler must not hold onto a shared resource across multiple completion notifications. If it does, it risks invoking the dining philosopher's problem 11. This problem is the deadlock that results when a logical thread of control waits forever for a semaphore to become signaled. This is illustrated by imagining a dinner party attended by a group of philosophers. The diners are seated around a circular table with exactly one chop stick between each philosopher. When a philosopher becomes hungry, he must obtained the chop stick to his left and to his right in order to eat. Once philosophers obtain a chop stick, they will not release it until their hunger is satisfied. If all philosophers pick up the chop stick on their right, a deadlock occurs because the chop stick on the left will never become available.

8.3.3 Preemptive Policy #

The Completion Dispatcher type determines if a Completion Handler can be preemptive while executing. When attached to Dynamic-thread and Thread Pool dispatchers, Completion Handlers are naturally preemptive. However, when tied to a Post-reactive Completion Dispatcher, Completion Handlers are not preemptive with respect to each other. When driven by a Call-through dispatcher, the Completion Handlers are not preemptive with respect to the thread-of-control that is in the alertable wait state. In general, a handler should not perform long-duration synchronous operations unless multiple completion threads are used since this will significantly decrease the overall responsiveness of the application. This risk can be alleviated by increased programming discipline. For instance, all Completion Handlers are required to act as Proactive Initiators instead of executing synchronous operations.

9 Sample Code #

This section shows howto use the Proactor pattern to develop a Web server. The example is based on the Proactor pattern implementation in the ACE framework [4]. When a client connects to the Web server, the HTTP Handler¡¯s open method is called. The server then initializes the asynchronous I/O object with the object to call-back when the Asynchronous Operation completes (which in this case is this), the network connection for transferring the data, and the Completion Dispatcher to be used once the operation completes (proactor ). The read operation is then started asynchronously and the server returns to the event loop. The HTTP Handler::handle read stream is called back by the dispatcher when the Async read operation completes. If there is enough data, the client request is then parsed. If the entire client request has not arrived yet, another read operation is initiated asynchronously. In response to a GET request, the server memory-maps the requested file and writes the file data asynchronously to the client. The dispatcher calls back on HTTP Handler::handle write stream when the write operation completes, which frees up dynamically allocated resources. The Appendix contains two other code examples for implementing the Web server using a synchronous threaded model and a synchronous (non-blocking) reactive model.
class HTTP_Handler : public Proactor::Event_Handler
// = TITLE
// Implements the HTTP protocol
// (asynchronous version).
//
// = PATTERN PARTICIPANTS
// Proactive Initiator = HTTP_Handler
// Asynch Op = Network I/O
// Asynch Op Processor = OS
// Completion Dispatcher = Proactor
// Completion Handler = HTPP_Handler
{
public:
    void open (Socket_Stream *client)
    {
        // Initialize state for request
        request_.state_ = INCOMPLETE;
        // Store reference to client.
        client_ = client;
        // Initialize asynch read stream
        stream_.open (*this, client_->handle(), proactor_);
        // Start read asynchronously.
        stream_.read (request_.buffer(), request_.buffer_size());
    }
    // This is called by the Proactor
    // when the asynch read completes
    void handle_read_stream(u_long bytes_transferred)
    {
    if (request_.enough_data(bytes_transferred))
        parse_request();
    else
        // Start reading asynchronously.
        stream_.read(request_.buffer(), request_.buffer_size());
    }
    void parse_request()
    {
        // Switch on the HTTP command type.
        switch (request_.command ()) {
            // Client is requesting a file.
            case HTTP_Request::GET:
                // Memory map the requested file.
                file_.map (request_.filename ());
                // Start writing asynchronously.
                stream_.write (file_.buffer (),
                file_.buffer_size ());
                break;
            // Client is storing a file
            // at the server.
            case HTTP_Request::PUT:
            // ...
        }
    }
    void handle_write_stream(u_long bytes_transferred)
    {
        if (file_.enough_data(bytes_transferred))
            // Success....
        else
            // Start another asynchronous write
            stream_.write(file_.buffer(), file_.buffer_size());
    }
private:
    // Set at initialization.
    Proactor *proactor_;
    // Memory-mapped file_;
    Mem_Map file_;
    // Socket endpoint.
    Socket_Stream *client_;
    // HTTP Request holder
    HTTP_Request request_;
    // Used for Asynch I/O
    Asynch_Stream stream_;
};

10 Known Uses #

The following are some widely documented uses of the Proctor pattern:
  • I/O Completion Ports in Windows NT: The Windows NT operating system implements the Proactor pattern. Various Asynchronous Operations such as accepting new network connections, reading and writing to files and sockets, and transmission of files across a network connection are supported by Windows NT. The operating system is the Asynchronous Operation Processor. Results of the operations are queued up at the I/O completion port (which plays the role of the Completion Dispatcher).
  • The UNIX AIO Family of Asynchronous I/O Operations: On some real-time POSIX platforms, the Proactor pattern is implemented by the aio family of APIs [9]. These OS
features are very similar to the ones described above for Windows NT. One difference is that UNIX signals can be used to implement an truly asynchronous Completion Dispatcher (the Windows NT API is not truly asyn-chronous).
  • ACE Proactor: The Adaptive Communications Environment (ACE) [4] implements a Proactor component that encapsulates I/O Completion Ports on Windows NT and the aio APIs on POSIX platforms. The ACE Proactor abstraction provides an OO interface to the standard C APIs supported by Windows NT. The source code for this implementation can be acquired from the ACE website at www.cs.wustl.edu/¢¨schmidt/ACE.html.
  • Asynchronous Procedure Calls in Windows NT: Some systems (such as Windows NT) support Asynchronous Procedure Calls (APC)s. An APC is a function that executes asynchronously in the context of a particular thread. When an APC is queued to a thread, the system issues a software interrupt. The next time the thread is scheduled, it will run the APC. APCs made by operating system are called kernel-mode APCs. APCs made by an application are called user-mode APCs.

11 Related Patterns #

Figure 9 illustrates patterns that are related to the Proactor.

proactor_figure_9.png

The Asynchronous Completion Token (ACT) pattern [8] is generally used in conjunction with the Proactor pattern. When Asynchronous Operations complete, applications may need more information than simply the notification itself to properly handle the event. The Asynchronous Completion Token pattern allows applications to efficiently associate state with the completion of Asynchronous Operations. The Proactor pattern is related to the Observer pattern 12 (where dependents are updated automatically when a single subject changes). In the Proactor pattern, handlers are informed automatically when events from multiple sources occur. In general, the Proactor pattern is used to asynchronously demultiplex multiple sources of input to their associated event handlers, whereas an Observer is usually associated with only a single source of events. The Proactor pattern can be considered an asynchronous variant of the synchronous Reactor pattern [5]. The Reactor pattern is responsible for demultiplexing and dispatching of multiple event handlers that are triggered when it is possible to initiate an operation synchronously without blocking. In contrast, the Proactor supports the demultiplexing and dispatching of multiple event handlers that are triggered by the completion of asynchronous events. The Active Object pattern 13 decouples method execution from method invocation. The Proactor pattern is similar because Asynchronous Operation Processors perform operations on behalf of application Proactive Initiators. That is, both patterns can be used to implement Asynchronous Operations. The Proactor pattern is often used in place of the Active Object pattern to decouple the systems concurrency policy from the threading model. A Proactor may be implemented as a Singleton 12. This is useful for centralizing event demultiplexing and completion dispatching into a single location within an asynchronous application. The Chain of Responsibility (COR) pattern 12 decouples event handlers from event sources. The Proactor pattern is similar in its segregation of Proactive Initiators and Completion Handlers. However, in COR, the event source has no prior knowledge of which handler will be executed, if any. In Proactor, Proactive Initiators have full disclosure of the target handler. However, the two patterns can be combined by establishing a Completion

Handler that is the entry pont into a responsibility chain dynamically configured by an external factory.

12 Concluding Remarks #

The Proactor pattern embodies a powerful design paradigm that supports efficient and flexible event dispatching strategies for high-performance concurrent applications. The Proactor pattern provides the performance benefits of executing operations concurrently, without constraining the developer to synchronous multi-threaded or reactive programming.

13 References #

[1] J. Hu, I. Pyarali, and D. C. Schmidt, ¡°Measuring the Impact of Event Dispatching and Concurrency Models on Web Server Performance Over High-speed Networks,¡± in Proceedings of the 2nd Global Internet Conference, IEEE, November 1997. [2] J. Hu, I. Pyarali, and D. C. Schmidt, ¡°Applying the Proactor Pattern to High-Performance Web Servers,¡± in Proceedings of the 10th International Conference on Parallel and Distributed Computing and Systems, IASTED, Oct. 1998. [3] J. C. Mogul, ¡°The Case for Persistent-connection HTTP,¡± in Proceedings of ACMSIGCOMM ¡¯95 Conference in Computer Communication Review, (Boston, MA, USA), pp. 299–314, ACM Press, August 1995. [4] D. C. Schmidt, ¡°ACE: an Object-Oriented Framework for Developing Distributed Applications,¡± in Proceedings of the 6 th USENIX C++ Technical Conference, (Cambridge, Mas-sachusetts), USENIX Association, April 1994. [5] D. C. Schmidt, ¡°Reactor: An Object Behavioral Pattern for Concurrent Event Demultiplexing and Event Handler Dis-patching,¡± in Pattern Languages of Program Design (J. O. Coplien and D. C. Schmidt, eds.), pp. 529–545, Reading, MA: Addison-Wesley, 1995. [6] D. C. Schmidt, ¡°Acceptor and Connector: Design Patterns for Initializing Communication Services,¡± in Pattern Languages of Program Design (R. Martin, F. Buschmann, and D. Riehle, eds.), Reading, MA: Addison-Wesley, 1997. [7] M. K. McKusick, K. Bostic, M. J. Karels, and J. S. Quarter-man, The Design and Implementation of the 4.4BSD Operating System. Addison Wesley, 1996. [8] I. Pyarali, T. H. Harrison, and D. C. Schmidt, ¡°Asynchronous Completion Token: an Object Behavioral Pattern for Efficient Asynchronous Event Handling,¡± in Pattern Languages of Program Design (R. Martin, F. Buschmann, and D. Riehle, eds.), Reading, MA: Addison-Wesley, 1997. [9] ¡°Information Technology – Portable Operating System Interface (POSIX) – Part 1: System Application: Program Interface (API) C Language,¡± 1995. 10 Microsoft Developers Studio, Version 4.2 - Software Development Kit, 1996. 11 E. W. Dijkstra, ¡°Hierarchical Ordering of Sequential Pro-cesses,¡± Acta Informatica, vol. 1, no. 2, pp. 115–138, 1971. 12 E. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Pat-terns: Elements of Reusable Object-Oriented Software. Reading, MA: Addison-Wesley, 1995. 13 R. G. Lavender and D. C. Schmidt, ¡°Active Object: an Object Behavioral Pattern for Concurrent Programming,¡± in Proceedings of the 2nd Annual Conference on the Pattern Languages of Programs, (Monticello, Illinois), pp. 1–7, September 1995.

13.1 A. Alternative Implementations #

This Appendix outlines the code used to develop alternatives to the Proactor pattern. Below, we examine both synchronous I/O using multi-threading and reactive I/O using single-threading.

13.1.1 A.1 Multiple Synchronous Threads #

The following code shows how to use synchronous I/O with a pool of threads to develop a Web server. When a client con-nects to the server a thread in the pool accepts the connection and calls the open method in class HTTP Handler. The server then synchronously reads the request from the network connection. When the read operation completes, the client request is then parsed. In response to a GET request, the server memory-maps the requested file and writes the file data synchronously to the client. Note how blocking I/O allows the Web server to follow the steps outlined in Section 2.2.1.
class HTTP_Handler
// = TITLE
// Implements the HTTP protocol
// (synchronous threaded version).
//
// = DESCRIPTION
// This class is called by a
// thread in the Thread Pool.
{
public:
void open (Socket_Stream *client)
{
HTTP_Request request;
// Store reference to client.
client_ = client;
// Synchronously read the HTTP request
// from the network connection and
// parse it.
client_->recv (request);
parse_request (request);
}
void parse_request (HTTP_Request &request)
{
// Switch on the HTTP command type.
switch (request.command ())
{
// Client is requesting a file.
case HTTP_Request::GET:
// Memory map the requested file.
Mem_Map input_file;
input_file.map (request.filename());
// Synchronously send the file
// to the client. Block until the
// file is transferred.
client_->send (input_file.data (),
input_file.size ());
break;
// Client is storing a file at
// the server.
case HTTP_Request::PUT:
// ...
}
}
private:
// Socket endpoint.
Socket_Stream *client_;
// ...
};

13.1.2 A.2 Single-threaded Reactive Event Dispatching #

The following code shows the use of the Reactor pattern to develop a Web server. When a client connects to the server, the HTTP Handler::open method is called. The server registers the I/O handle and the object to callback (which in this case is this) when the network handle is ¡°ready for reading.¡± The server returns to the event loop. When the request data arrives at the server, the reactor calls back the HTTP Handler::handle input method. The client data is read in a non-blocking manner. If there is enough data, the client request is parsed. If the entire client request has not yet arrived, the application returns to the re-actor event loop. In response to a GET request, the server memory maps the requested file and registers with the reactor to be notified when the network connection becomes ¡°ready for writing.¡± The reactor then calls back on HTTP Handler::handle output method when writing data to the connection would not blocking the calling thread. When all the data has been sent to the client, the network connection is closed.

class HTTP_Handler :
public Reactor::Event_Handler
// = TITLE
// Implements the HTTP protocol
// (synchronous reactive version).
//
// = DESCRIPTION
// The Event_Handler base class
// defines the hooks for
// handle_input()/handle_output().
//
// = PATTERN PARTICIPANTS
// Reactor = Reactor
// Event Handler = HTTP_Handler
{
public:
void open (Socket_Stream *client)
{
// Initialize state for request
request_.state_ = INCOMPLETE;
// Store reference to client.
client_ = client;
// Register with the reactor for reading.
reactor_->register_handler
(client_->handle (),
this,
Reactor::READ_MASK);
}
// This is called by the Reactor when
// we can read from the client handle.
void handle_input (void)
{
int result = 0;
// Non-blocking read from the network
// connection.
do
result = request_.recv (client_->handle ());
while (result != SOCKET_ERROR
&& request_.state_ == INCOMPLETE);
// No more progress possible,
// blocking will occur
if (request_.state_ == INCOMPLETE
&& errno == EWOULDBLOCK)
reactor_->register_handler
(client_->handle (),
this,
Reactor::READ_MASK);
else
// We now have the entire request
parse_request ();
}
void parse_request (void)
{
// Switch on the HTTP command type.
switch (request_.command ()) {
// Client is requesting a file.
case HTTP_Request::GET:
// Memory map the requested file.
file_.map (request_.filename ());
// Transfer the file using Reactive I/O.
handle_output ();
break;
// Client is storing a file at
// the server.
case HTTP_Request::PUT:
// ...
}
}
void handle_output (void)
{
// Asynchronously send the file
// to the client.
if (client_->send (file_.data (),
file_.size ())
== SOCKET_ERROR
&& errno == EWOULDBLOCK)
// Register with reactor...
else
// Close down and release resources.
handle_close ();
}
private:
// Set at initialization.
Reactor *reactor_;
// Memory-mapped file_;
Mem_Map file_;
// Socket endpoint.
Socket_Stream *client_;
// HTTP Request holder.
HTTP_Request request_;
};


?¹ø¿ªÁß


EditText | FindPage | DeletePage | LikePages | UploadedFiles

Powered by MoniWiki
xhtml1 | css2 | any browser | rss
Last modified 2004-02-26 12:56:47
Loading 0.5590 sec