============================== 11.13 å‘é€ä¸ŽæŽ¥æ”¶å¤§åž‹æ•°ç»„ ============================== ---------- 问题 ---------- ä½ è¦é€šè¿‡ç½‘络连接å‘é€å’ŒæŽ¥å—è¿žç»æ•°æ®çš„大型数组,并尽é‡å‡å°‘æ•°æ®çš„å¤åˆ¶æ“作。 ---------- 解决方案 ---------- 下é¢çš„函数利用 ``memoryviews`` æ¥å‘é€å’ŒæŽ¥å—大数组: .. code-block:: python # zerocopy.py def send_from(arr, dest): view = memoryview(arr).cast('B') while len(view): nsent = dest.send(view) view = view[nsent:] def recv_into(arr, source): view = memoryview(arr).cast('B') while len(view): nrecv = source.recv_into(view) view = view[nrecv:] 为了测试程åºï¼Œé¦–先创建一个通过socket连接的æœåŠ¡å™¨å’Œå®¢æˆ·ç«¯ç¨‹åºï¼š .. code-block:: python >>> from socket import * >>> s = socket(AF_INET, SOCK_STREAM) >>> s.bind(('', 25000)) >>> s.listen(1) >>> c,a = s.accept() >>> 在客户端(å¦å¤–一个解释器ä¸ï¼‰ï¼š .. code-block:: python >>> from socket import * >>> c = socket(AF_INET, SOCK_STREAM) >>> c.connect(('localhost', 25000)) >>> æœ¬èŠ‚çš„ç›®æ ‡æ˜¯ä½ èƒ½é€šè¿‡è¿žæŽ¥ä¼ è¾“ä¸€ä¸ªè¶…å¤§æ•°ç»„ã€‚è¿™ç§æƒ…况的è¯ï¼Œå¯ä»¥é€šè¿‡ ``array`` æ¨¡å—æˆ– ``numpy`` æ¨¡å—æ¥åˆ›å»ºæ•°ç»„: .. code-block:: python # Server >>> import numpy >>> a = numpy.arange(0.0, 50000000.0) >>> send_from(a, c) >>> # Client >>> import numpy >>> a = numpy.zeros(shape=50000000, dtype=float) >>> a[0:10] array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) >>> recv_into(a, c) >>> a[0:10] array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]) >>> ---------- 讨论 ---------- 在数æ®å¯†é›†åž‹åˆ†å¸ƒå¼è®¡ç®—和平行计算程åºä¸ï¼Œè‡ªå·±å†™ç¨‹åºæ¥å®žçްå‘é€/接å—大釿•°æ®å¹¶ä¸å¸¸è§ã€‚ ä¸è¿‡ï¼Œè¦æ˜¯ä½ ç¡®å®žæƒ³è¿™æ ·åšï¼Œä½ å¯èƒ½éœ€è¦å°†ä½ 的数æ®è½¬æ¢æˆåŽŸå§‹å—节,以便给低层的网络函数使用。 ä½ å¯èƒ½è¿˜éœ€è¦å°†æ•°æ®åˆ‡å‰²æˆå¤šä¸ªå—ï¼Œå› ä¸ºå¤§éƒ¨åˆ†å’Œç½‘ç»œç›¸å…³çš„å‡½æ•°å¹¶ä¸èƒ½ä¸€æ¬¡æ€§å‘逿ˆ–接å—超大数æ®å—。 ä¸€ç§æ–¹æ³•是使用æŸç§æœºåˆ¶åºåˆ—化数æ®â€”—å¯èƒ½å°†å…¶è½¬æ¢æˆä¸€ä¸ªå—节å—符串。 ä¸è¿‡ï¼Œè¿™æ ·æœ€ç»ˆä¼šåˆ›å»ºæ•°æ®çš„一个å¤åˆ¶ã€‚ å°±ç®—ä½ åªæ˜¯é›¶ç¢Žçš„åšè¿™äº›ï¼Œä½ çš„ä»£ç æœ€ç»ˆè¿˜æ˜¯ä¼šæœ‰å¤§é‡çš„å°åž‹å¤åˆ¶æ“作。 本节通过使用内å˜è§†å›¾å±•ç¤ºäº†ä¸€äº›é”æ³•æ“作。 本质上,一个内å˜è§†å›¾å°±æ˜¯ä¸€ä¸ªå·²å˜åœ¨æ•°ç»„的覆盖层。ä¸ä»…ä»…æ˜¯é‚£æ ·ï¼Œ 内å˜è§†å›¾è¿˜èƒ½ä»¥ä¸åŒçš„æ–¹å¼è½¬æ¢æˆä¸åŒç±»åž‹æ¥è¡¨çŽ°æ•°æ®ã€‚ 这个就是下é¢è¿™ä¸ªè¯å¥çš„目的: .. code-block:: python view = memoryview(arr).cast('B') 它接å—一个数组 arr并将其转æ¢ä¸ºä¸€ä¸ªæ— 符å·å—节的内å˜è§†å›¾ã€‚è¿™ä¸ªè§†å›¾èƒ½è¢«ä¼ é€’ç»™socket相关函数, 比如 ``socket.send()`` 或 ``send.recv_into()`` 。 在内部,这些方法能够直接æ“作这个内å˜åŒºåŸŸã€‚例如,``sock.send()`` 直接从内å˜ä¸å‘生数æ®è€Œä¸éœ€è¦å¤åˆ¶ã€‚ ``send.recv_into()`` 使用这个内å˜åŒºåŸŸä½œä¸ºæŽ¥å—æ“作的输入缓冲区。 剩下的一个难点就是socket函数å¯èƒ½åªæ“作部分数æ®ã€‚ 通常æ¥è®²ï¼Œæˆ‘们得使用很多ä¸åŒçš„ ``send()`` å’Œ ``recv_into()`` æ¥ä¼ 输整个数组。 ä¸ç”¨æ‹…å¿ƒï¼Œæ¯æ¬¡æ“作åŽï¼Œè§†å›¾ä¼šé€šè¿‡å‘逿ˆ–接å—å—节数é‡è¢«åˆ‡å‰²æˆæ–°çš„视图。 æ–°çš„è§†å›¾åŒæ ·ä¹Ÿæ˜¯å†…å˜è¦†ç›–å±‚ã€‚å› æ¤ï¼Œè¿˜æ˜¯æ²¡æœ‰ä»»ä½•çš„å¤åˆ¶æ“作。 这里有个问题就是接å—è€…å¿…é¡»äº‹å…ˆçŸ¥é“æœ‰å¤šå°‘æ•°æ®è¦è¢«å‘é€ï¼Œ 以便它能预分é…一个数组或者确ä¿å®ƒèƒ½å°†æŽ¥å—çš„æ•°æ®æ”¾å…¥ä¸€ä¸ªå·²ç»å˜åœ¨çš„æ•°ç»„ä¸ã€‚ 如果没办法知é“çš„è¯ï¼Œå‘é€è€…就得先将数æ®å¤§å°å‘é€è¿‡æ¥ï¼Œç„¶åŽå†å‘é€å®žé™…的数组数æ®ã€‚