I was tempted to code it up, and it turns out you can do it in pure python.
I thought of 4 ways to copy the data: using a for loop (like you did), using numpy.fromiter, using numpy.fromstring, and using Marshal.Copy.
Obviously the for loop is the slowest. numpy.fromiter is still slow, but ~2.5x faster than the for loop (still has all .NET array checks since this is in Python and the indexers cannot be optimized away). The last two do direct memory copies (fromstring gets the memory pointer of the .NET array while Marshal.Copy gets the memory pointer of the NumPy array). They are both MUCH faster than a for loop, especially for larger arrays (>200x faster). numpy.fromstring is faster for smaller arrays, but by the time I got to 10000000 doubles it was twice as slow as Marshal.Copy.
import clr
from System import Array, Double, IntPtr, Random
import numpy as np
import time
def check_arrays(a, b):
if len(a) != len(b): print("Arrays are different size!")
if any(A != B for A,B in zip(a, b)): print("Arrays have different values!")
print("Creating source...")
r = Random()
src = Array.CreateInstance(Double, 10000000)
for i in xrange(len(src)): src[i] = r.NextDouble()
print('Copy using for loop'),
start = time.clock()
dest = np.empty(len(src))
for i in xrange(len(src)): dest[i] = src[i]
end = time.clock()
print('in %f sec' % (end-start))
check_arrays(src, dest)
print('Copy using fromiter'),
start = time.clock()
dest = np.fromiter(src, float)
end = time.clock()
print('in %f sec' % (end-start))
check_arrays(src, dest)
print('Copy using fromstring'),
from ctypes import string_at
from System.Runtime.InteropServices import GCHandle, GCHandleType
start = time.clock()
src_hndl = GCHandle.Alloc(src, GCHandleType.Pinned)
try:
src_ptr = src_hndl.AddrOfPinnedObject().ToInt32()
dest = np.fromstring(string_at(src_ptr, len(src)*8)) # note: 8 is size of double...
finally:
if src_hndl.IsAllocated: src_hndl.Free()
end = time.clock()
print('in %f sec' % (end-start))
check_arrays(src, dest)
print('Copy using Marshal.Copy'),
from System.Runtime.InteropServices import Marshal
start = time.clock()
dest = np.empty(len(src))
Marshal.Copy(src, 0, IntPtr.__overloads__[int](dest.__array_interface__['data'][0]), len(src))
end = time.clock()
print('in %f sec' % (end-start))
check_arrays(src, dest)