@@ -1244,6 +1244,10 @@ write_array_to_file(PyObject *Py_UNUSED(m), PyObject *args, PyObject *kwargs)
12441244 char * pack_buffer = NULL ;
12451245 Py_ssize_t pack_buffer_size = 0 ;
12461246
1247+ /* For the write() path, reuse a single memoryview across iterations,
1248+ * rebinding it to each chunk, instead of allocating a new object each time. */
1249+ PyObject * buffer = NULL ;
1250+
12471251 do {
12481252 npy_intp inner_size = * innersizeptr ;
12491253 if (inner_size == 0 ) {
@@ -1283,20 +1287,31 @@ write_array_to_file(PyObject *Py_UNUSED(m), PyObject *args, PyObject *kwargs)
12831287 }
12841288 }
12851289 else {
1286- /* Note: PyMemoryView_FromMemory requires non-const char*, but we pass
1290+ /* Reuse a single memoryview, rebinding it to the current chunk. This
1291+ * is safe because write() consumes the bytes synchronously and does
1292+ * not retain the view (exports return to 0 before write() returns).
1293+ * Note: PyMemoryView_FromMemory requires non-const char*, but we pass
12871294 * PyBUF_READ flag which makes the view read-only, so the cast is safe. */
1288- PyObject * buffer = PyMemoryView_FromMemory ((char * )data_to_write , chunk_size , PyBUF_READ );
12891295 if (buffer == NULL ) {
1290- goto fail ;
1296+ buffer = PyMemoryView_FromMemory ((char * )data_to_write , chunk_size , PyBUF_READ );
1297+ if (buffer == NULL ) {
1298+ goto fail ;
1299+ }
1300+ }
1301+ else {
1302+ // Rebind buf/len (and shape[0], since ndim == 1 and itemsize == 1) to this chunk
1303+ Py_buffer * view = PyMemoryView_GET_BUFFER (buffer );
1304+ view -> buf = (void * )data_to_write ;
1305+ view -> len = chunk_size ;
1306+ view -> shape [0 ] = chunk_size ;
12911307 }
12921308
12931309 PyObject * write_result = PyObject_CallMethodObjArgs (file , write_name , buffer , NULL );
1294- Py_DECREF (buffer );
12951310 if (write_result == NULL ) {
12961311 goto fail ;
12971312 }
12981313
1299- /* Check for partial writes */
1314+ // Check for partial writes
13001315 if (PyLong_Check (write_result )) {
13011316 Py_ssize_t bytes_written = PyLong_AsSsize_t (write_result );
13021317 if (bytes_written < 0 && PyErr_Occurred ()) {
@@ -1322,12 +1337,14 @@ write_array_to_file(PyObject *Py_UNUSED(m), PyObject *args, PyObject *kwargs)
13221337 }
13231338
13241339 PyMem_Free (pack_buffer );
1340+ Py_XDECREF (buffer );
13251341 NpyIter_Deallocate (iter );
13261342 Py_XDECREF (write_name );
13271343 Py_RETURN_NONE ;
13281344
13291345 fail :
13301346 PyMem_Free (pack_buffer );
1347+ Py_XDECREF (buffer );
13311348 NpyIter_Deallocate (iter );
13321349 Py_XDECREF (write_name );
13331350 return NULL ;
0 commit comments