Cython is slower than ctypes in win32 based gui

33 views
Skip to first unread message

vinod kc

unread,
Feb 12, 2026, 11:27:08 AMFeb 12
to cython-users
Hi all,
I have created a gui library in C3 with win32 api. Compiled it as a dll and called the functions in that dll from python via ctypes. Then I created a cython file to call the same dll functions. Then I tested both projects. The ctypes version ran faster than cython version. Ctypes version took 7.3 ms to display the window but cython version took 8.15 ms. This was a surprise to me. Do I need to tweak anything in cython to improve the performance ? 
In Cython my current approach to pass the wchar ptr to dll was,
1. Create a common wchar buffer with PyMem_Alloc (module level cdef variable)
2. Use PyUnicode_AsWideChar to fill the buffer
3. Pass the buffer address to dll. 

But in ctypes, I have,
1. Created an instance of ctypes.c_wchar_p with python string so that I can use the internal string buffer of python.
2. Keep the instance available until win32 api finished it's job with that string.

da-woods

unread,
Feb 12, 2026, 4:45:46 PMFeb 12
to cython...@googlegroups.com

I'm not quite sure I understand your ctypes approach perfectly. But I think the difference is: in the Cython version you convert the strings on every function call. In the ctypes version you convert the strings once with `ctypes.c_wchar_p` and then pass the existing object to each function call.

Potentially you could do the same thing in Cython. The easiest way to convert a string to a wchar buffer Python object is probably `array.array('H', s.encode('utf_16'))` or `memoryview(s.encode('utf_16')).cast('H')`. You could then have your functions accept `wchar[::1]` memoryviews (which should match on Windows I think). Alternatively you could just pass the encoded bytes around and cast the pointers, but that's maybe a little less safe.

Although possibly I'm misunderstanding your problem.

--

---
You received this message because you are subscribed to the Google Groups "cython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cython-users...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/cython-users/740a8b2d-6ceb-43b8-8078-c2ecd9199bfcn%40googlegroups.com.

vinod kc

unread,
Feb 13, 2026, 1:19:48 AMFeb 13
to cython-users
Hi @D Woods,
Thank you for the detailed reply. I will surely try the solution you gave me. But before that, I would like to clarify what I did with ctypes. 
In my class constructor , I did this,
def __init__(self, txt, ....):
    self._title = txt 
    self._wtitle =  ctypes.c_wchar_p(self._title)    
    self._ptr = c3dll.create_new_window(self._wtitle, .....) 

vinod kc

unread,
Feb 13, 2026, 7:49:54 AMFeb 13
to cython-users
@D Woods,
There is a small correction, I don't want the wchar buffer Python object, I just want a wchar ptr to pass to my c3 dll. BTW, I tried this code didn't get much benefit.
cimport cpython.array as carray
ctypedef carray.array PyArray

cdef class CForm:
    cdef str _pyTitle  
    cdef PyArray _titleBuf

    def __cinit__(self, title, width, height, pos, style, autoc = True):
        self._pyTitle = title
        self._titleBuf = carray.array('H', title.encode('utf_16'))
        cdef unsigned short[::1] view = self._titleBuf
        self._ptr = c3dll. create_new_window  (self._pyid, <LPCWSTR>&view[0], width, height, pos, style, autoc)

da-woods

unread,
Feb 13, 2026, 3:41:07 PMFeb 13
to cython...@googlegroups.com

My suggestion probably only worthwhile if you reuse the string across a lot of different calls - it doesn't look like you're doing that.

Beyond that I don't really know. The actual creation of a window probably isn't a useful thing to be benchmarking - presumably it's something that happens pretty rarely. But obviously updating the window may be something where you care about the performance.

vinod kc

unread,
Feb 14, 2026, 2:37:25 AMFeb 14
to cython-users
I have the same opinion about benchmarking. So I think I can write this library in Cython itself. But I have a doubt about the design choice. I can do it in two ways.
1. I can write UI library completely in Cython itself.
2. I can write the UI code in C3 and compile it as a DLL. Then it can be used in Cython. I can wrap the DLL functions inside a Cython class. 
Can you tell me which one is more efficient? 

da-woods

unread,
Feb 14, 2026, 4:39:06 AMFeb 14
to cython...@googlegroups.com

It probably makes most sense to write it in C3. But that's largely not based on "efficiency":

I suspect you'll be implementing it by calling lower-level OS functions, and C3 is a cleaner way of doing that.
Cython is largely a way of blurring the Python-C boundary, and writing faster Python-like code. I'm not sure if that's what you're doing.
C3 probably produces a general-purpose library while Cython produces something that can only be used from Python.

vinod kc

unread,
Feb 14, 2026, 10:08:03 AMFeb 14
to cython-users
Okay. Thank you for your advice. 
Reply all
Reply to author
Forward
0 new messages