Skip to main content

Windows version of uvloop

Project description

Code style: black

IDIM

Winloop

PyPI version PyPI - Downloads License: MIT License: Apache-2.0

An alternative library for uvloop compatibility with Windows because let's face it. Windows' Python asyncio standard library is garbage, especially when Windows Defender decides to eat half of your RAM. I never really liked the fact that I couldn't make anything run faster especially when you have fiber internet connections in place and you've done all the optimizations you could possibly think of. It always felt disappointing when libuv is available for Windows but Windows was never compatible with uvloop.

Since nobody was willing to step in after so many years of waiting, I went ahead and downloaded the source code for uvloop and started modifying the source code to be Windows compatible by carefully removing and changing parts that were not made for Windows. Many hours of research went into making this library.

The differences with uvloop is that forking has been fully disabled and some smaller API calls had to be changed, error handling has been carefully modified and subprocesses release the GIL instead of forking out...

There is a performance increase of about 5 times with Winloop compared to using the WindowsSelectorEventLoopPolicy and WindowsProactorEventLoopPolicy which have been known to trigger SSL problems in Python 3.9. Winloop is a very good replacement for solving those SSL problems as well. This library also has comparable performance to its brother uvloop.

How to install Winloop on your Windows Operating System

pip install winloop

You can also clone the repository and build the extension yourself by running the command below if you wish to use or build this library locally. Note that you will need Cython and The Visual C++ extensions to compile this library on your own.

python setup.py build_ext --inplace

Reporting issues

If you find any bugs with this library be sure to open up an issue in the issuetracker. Me and other contributors will be happy try to help you figure out and diagnose your problems.

Making pull requests

We encourage anyone to make pull-requests to Winloop, containing anything from spelling mistakes to vulnerability patches. Every little bit helps keep this library maintained and alive. Make sure that you are able to compile the library with the steps shown above. We plan to implement a nightly workflow to verify one's pull-request in the future.

try:
    import aiohttp
    import aiohttp.web
except ImportError:
    skip_tests = True
else:
    skip_tests = False

import asyncio
import unittest
import weakref
import winloop
import sys

class TestAioHTTP(unittest.TestCase):
    def __init__(self, methodName: str = "test_aiohttp_basic_1") -> None:
        super().__init__(methodName)


    def setUp(self):
        self.loop = asyncio.get_event_loop()

    def test_aiohttp_basic_1(self):
        PAYLOAD = '<h1>It Works!</h1>' * 10000

        async def on_request(request):
            return aiohttp.web.Response(text=PAYLOAD)

        asyncio.set_event_loop(self.loop)
        app = aiohttp.web.Application()
        app.router.add_get('/', on_request)

        runner = aiohttp.web.AppRunner(app)
        self.loop.run_until_complete(runner.setup())
        site = aiohttp.web.TCPSite(runner, '0.0.0.0', '10000')
        self.loop.run_until_complete(site.start())
        port = site._server.sockets[0].getsockname()[1]

        async def test():
            # Make sure we're using the correct event loop.
            self.assertIs(asyncio.get_event_loop(), self.loop)

            for addr in (('localhost', port),
                         ('127.0.0.1', port)):
                async with aiohttp.ClientSession() as client:
                    async with client.get('http://{}:{}'.format(*addr)) as r:
                        self.assertEqual(r.status, 200)
                        result = await r.text()
                        self.assertEqual(result, PAYLOAD)

        self.loop.run_until_complete(test())
        self.loop.run_until_complete(runner.cleanup())

    def test_aiohttp_graceful_shutdown(self):
        async def websocket_handler(request):
            ws = aiohttp.web.WebSocketResponse()
            await ws.prepare(request)
            request.app['websockets'].add(ws)
            try:
                async for msg in ws:
                    await ws.send_str(msg.data)
            finally:
                request.app['websockets'].discard(ws)
            return ws

        async def on_shutdown(app):
            for ws in set(app['websockets']):
                await ws.close(
                    code=aiohttp.WSCloseCode.GOING_AWAY,
                    message='Server shutdown')

        asyncio.set_event_loop(self.loop)
        app = aiohttp.web.Application()
        app.router.add_get('/', websocket_handler)
        app.on_shutdown.append(on_shutdown)
        app['websockets'] = weakref.WeakSet()

        runner = aiohttp.web.AppRunner(app)
        self.loop.run_until_complete(runner.setup())
        site = aiohttp.web.TCPSite(runner, '0.0.0.0', '10000')
        self.loop.run_until_complete(site.start())
        port = site._server.sockets[0].getsockname()[1]

        async def client():
            async with aiohttp.ClientSession() as client:
                async with client.ws_connect(
                        'http://127.0.0.1:{}'.format(port)) as ws:
                    await ws.send_str("hello")
                    async for msg in ws:
                        assert msg.data == "hello"

        client_task = asyncio.ensure_future(client())

        async def stop():
            await asyncio.sleep(0.1)
            try:
                await asyncio.wait_for(runner.cleanup(), timeout=0.1)
            except Exception as e:
                print(e)
            finally:
                try:
                    client_task.cancel()
                    await client_task
                except asyncio.CancelledError:
                    pass

        self.loop.run_until_complete(stop())



if __name__ == "__main__":
    # print("tesing without winloop")
    # asyncio.DefaultEventLoopPolicy = asyncio.WindowsSelectorEventLoopPolicy
    # asyncio.DefaultEventLoopPolicy = asyncio.WindowsProactorEventLoopPolicy
    unittest.main()
    # Looks like winloop might be 3x faster than the Proctor Event Loop , THAT's A HUGE IMPROVEMENT!
    print("testing again but with winloop enabled")
    winloop.install()
    unittest.main()

The benchmarks for the code above are as follows

Benchmarks

TCP Connections


Asyncio Event Loop Policy Time (in Seconds)
WinLoopPolicy 0.493s
WindowsProactorEventLoopPolicy 2.510s
WindowsSelectorEventLoopPolicy 2.723s

That's a massive increase and jump from just TCP alone! I'll be posting more benchmarks soon, as I modify more of the current test suites made by uvloop...

How to Use Winloop with Fastapi

This was a cool little script I put together just to make Fastapi that much faster to handle:

# TODO this code example is deprecated
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import winloop
import uvicorn
import asyncio
import datetime

app = FastAPI()

@app.on_event("startup")
def make_assertion():
    # Check to make sure that we bypassed the original eventloop Policy....
    assert isinstance(asyncio.get_event_loop_policy(), winloop.WinLoopPolicy)


@app.get("/test")
async def test_get_request():
    return HTMLResponse("<html><body><h1>FAST API WORKS WITH WINLOOP!</h1></body></html>")


# starllete will use asyncio.to_thread() so that this can remain asynchronous
@app.get("/date")
def test_dynamic_response():
    return str(datetime.datetime.now())


# Although tricky to pass and is not normal, it does in fact work...
if __name__ == "__main__":
    winloop.install()
    # Winloop's eventlooppolicy will be passed to uvicorn after this point...
    loop = asyncio.get_event_loop()
    config = uvicorn.Config(app=app,port=10000,loop=loop)
    server = uvicorn.Server(config)
    asyncio.run(server.serve())

How To Use Winloop When Uvloop is not available

# Here's A small Example of using winloop when uvloop is not available to us
import sys
import aiohttp
import asyncio

async def main():
    async with aiohttp.ClientSession("https://httpbin.org") as client:
        async with client.get("/ip") as resp:
            print(await resp.json())

if __name__ == "__main__":
    if sys.platform in ('win32', 'cygwin', 'cli'):
        from winloop import run
    else:
        # if we're on apple or linux do this instead
        from uvloop import run
    run(main())

TODO-List

  • In Winloop 0.2.0 or before 2026 I would like to start planning to migrate to pytest so that things could be formatted a little better. A Migration Python script might be needed or looked into.

  • Update Fastapi Example to a more recent version of fastapi

  • Help Wanted. We're looking for other maintainers to help us.

  • Nightly Builds And Test Suite Workflows for anyone wanting to use newer unreleased versions. (Done, it runs now)

  • Adding in the necessary hooks for pyinstaller to compile this fast library to executable code even though hooks have been known to inflate the size of the .exe files. This is because calling hidden-imports for all the __init__.py modules might annoy some developers. (Luckily I'm aware of this issue because I've been doing this myself...) Update, This is now pending and I hope that it passes

  • write a workflow for nightly builds if necessary for verification of pull requests.

  • Update benchmarks (They are old) can't believe I maintained this project for over a year now...

Videos

Contributing

I put my heart and soul into this library ever since it began and any help is apperciated and means a lot to me, I have other things I wish to explore so every little bit helps

How Can I contribute?

  • I make and branch and make edits and then I do a pull requests before I just step in and add something new. This way you have time to review my additions, changes or feature beforehand.
  • Forking The library.
  • Fixing or editing workflows.
  • Finding and editing spelling mistakes.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

winloop-0.6.3.tar.gz (2.6 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

winloop-0.6.3-cp314-cp314t-win_arm64.whl (576.2 kB view details)

Uploaded CPython 3.14tWindows ARM64

winloop-0.6.3-cp314-cp314t-win_amd64.whl (805.0 kB view details)

Uploaded CPython 3.14tWindows x86-64

winloop-0.6.3-cp314-cp314-win_arm64.whl (547.1 kB view details)

Uploaded CPython 3.14Windows ARM64

winloop-0.6.3-cp314-cp314-win_amd64.whl (655.5 kB view details)

Uploaded CPython 3.14Windows x86-64

winloop-0.6.3-cp313-cp313-win_arm64.whl (528.4 kB view details)

Uploaded CPython 3.13Windows ARM64

winloop-0.6.3-cp313-cp313-win_amd64.whl (644.5 kB view details)

Uploaded CPython 3.13Windows x86-64

winloop-0.6.3-cp312-cp312-win_arm64.whl (529.1 kB view details)

Uploaded CPython 3.12Windows ARM64

winloop-0.6.3-cp312-cp312-win_amd64.whl (644.9 kB view details)

Uploaded CPython 3.12Windows x86-64

winloop-0.6.3-cp311-cp311-win_arm64.whl (530.5 kB view details)

Uploaded CPython 3.11Windows ARM64

winloop-0.6.3-cp311-cp311-win_amd64.whl (647.4 kB view details)

Uploaded CPython 3.11Windows x86-64

winloop-0.6.3-cp310-cp310-win_arm64.whl (528.6 kB view details)

Uploaded CPython 3.10Windows ARM64

winloop-0.6.3-cp310-cp310-win_amd64.whl (640.3 kB view details)

Uploaded CPython 3.10Windows x86-64

winloop-0.6.3-cp39-cp39-win_arm64.whl (530.0 kB view details)

Uploaded CPython 3.9Windows ARM64

winloop-0.6.3-cp39-cp39-win_amd64.whl (641.6 kB view details)

Uploaded CPython 3.9Windows x86-64

winloop-0.6.3-cp38-cp38-win_amd64.whl (645.9 kB view details)

Uploaded CPython 3.8Windows x86-64

File details

Details for the file winloop-0.6.3.tar.gz.

File metadata

  • Download URL: winloop-0.6.3.tar.gz
  • Upload date:
  • Size: 2.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3.tar.gz
Algorithm Hash digest
SHA256 1ea7b90487f720eccf984dc65b793550bc86fcdc7c2f9b9f4fbfeac23f2b8dd0
MD5 626a460c3e1d355593133edd4273fba8
BLAKE2b-256 b70fcac40c803a7f0bf6a0ce6dd8f696e4029e16451233a4f2b5e96e8686fd80

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp314-cp314t-win_arm64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp314-cp314t-win_arm64.whl
  • Upload date:
  • Size: 576.2 kB
  • Tags: CPython 3.14t, Windows ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp314-cp314t-win_arm64.whl
Algorithm Hash digest
SHA256 447006f38f13827ff4600e7beeda70367370cb8dab8ea84042e8fa1749f32b1c
MD5 788a630cd0afe03985a55be976028e66
BLAKE2b-256 0f8d52eaa9187b88596b0a8b646874cfec5a5c3fce8c52b5182be1a0253203a3

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp314-cp314t-win_amd64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp314-cp314t-win_amd64.whl
  • Upload date:
  • Size: 805.0 kB
  • Tags: CPython 3.14t, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp314-cp314t-win_amd64.whl
Algorithm Hash digest
SHA256 d8fe1fce02c390836248f97403666d3b2e20c661820535e9b60330a60e86ffe6
MD5 126217dbefc46ec7d7c2931294aebd74
BLAKE2b-256 832668e5efa454b418a2df92ece323029f2f917573726ab8b1a98e334c77d367

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp314-cp314-win_arm64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp314-cp314-win_arm64.whl
  • Upload date:
  • Size: 547.1 kB
  • Tags: CPython 3.14, Windows ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp314-cp314-win_arm64.whl
Algorithm Hash digest
SHA256 e04cc1bf248919444afa5aefe04328c2064a89a6d98fe3c0fcb9e65323068126
MD5 2dceab6b64a59a071b1febe33e0e6ce0
BLAKE2b-256 7a020dddf67968e25c44fe112ac8652eb83c86e8d5c75ae333b2795ee6da4a6f

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 655.5 kB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 2d57782d2191c5e83475f58fb6423af9fb4bf3823fb05771e9a3caa5bb870e0d
MD5 8fc5e47b5109f0f3587169d1d1f1c683
BLAKE2b-256 b5a3ba3220d03cfe592baa78776892910dd11945b133b6e41714191f3e486b53

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp313-cp313-win_arm64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp313-cp313-win_arm64.whl
  • Upload date:
  • Size: 528.4 kB
  • Tags: CPython 3.13, Windows ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp313-cp313-win_arm64.whl
Algorithm Hash digest
SHA256 42e3fee166cdd53410122f29fa1df1c6844f2a4327d8357edfb6bb24ceb65b27
MD5 705e394689de0ba768f7d0dd3867674b
BLAKE2b-256 8baaa0d971f1b70b7f223fd0d5e03a521fa84b605697c9b0eb764561fbb4386b

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 644.5 kB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 393289e579d4aa36db1521e27bfa5680b2bf995a4c4cd915df3e34abca736e2d
MD5 ae227dd6c7f7c457552b98910f2141a1
BLAKE2b-256 5c00b1b78d7db4257f583b9bb514fdeca98ebd556232189f31133d88d378103b

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp312-cp312-win_arm64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp312-cp312-win_arm64.whl
  • Upload date:
  • Size: 529.1 kB
  • Tags: CPython 3.12, Windows ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp312-cp312-win_arm64.whl
Algorithm Hash digest
SHA256 33d2d275b7eca468958478555076e2e2814f5d7f94feffdc27b4e6409c645094
MD5 5e142d45ec87587ac78979aded927b2a
BLAKE2b-256 9ba1faa6833ac3ece9eaf23e14a695eb8baf25987e959e3abee003589e06805a

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 644.9 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 52d2961d16d38cc6313a122567e387522092c452a78c8d0354801f31b1565ec1
MD5 916cb1dc168557a6576978e1ba412d41
BLAKE2b-256 3b915c3fa198fa5191dbe4cfed32305687a184d3bb4998cd2d6149b2b8055b13

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp311-cp311-win_arm64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp311-cp311-win_arm64.whl
  • Upload date:
  • Size: 530.5 kB
  • Tags: CPython 3.11, Windows ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp311-cp311-win_arm64.whl
Algorithm Hash digest
SHA256 83c0ae348f66e162a79fdff5b681835d55383a3ac7fc9fdbce6681d5914f6a51
MD5 e79b654b678b86116d9035d33eb354fb
BLAKE2b-256 26b38364ca9c85627d91ae87c19a6a1ab571608ffbd4148b04d9b8206e67d2b7

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 647.4 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 23f8888c193ff4667d223e7664c3d74246bb8132b3b0c17d758828ef5102effb
MD5 49f04d86b1f3ad1b31c0234885155260
BLAKE2b-256 48e36b7f750da99cf618f82fb64249a43b5eb6fc562daad1bc21e59a15e7e27d

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp310-cp310-win_arm64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp310-cp310-win_arm64.whl
  • Upload date:
  • Size: 528.6 kB
  • Tags: CPython 3.10, Windows ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp310-cp310-win_arm64.whl
Algorithm Hash digest
SHA256 f102c30e2e7d140b1b21ebf293f0b27f0834142eea6cb704ff7e54620cbe718e
MD5 11e0a8360fb685b1f4d6f51877b5cb68
BLAKE2b-256 883b375469afd76d6771181d6037c66c3e0f6257ebe01fb58bfe6be4c57ab561

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 640.3 kB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 17332c0348f3274fb0e3e5acead90c9aaa1e1d5f699703475974c51116a7d99b
MD5 e0a9d58d5ff195e40ccbdff28f9cbcbb
BLAKE2b-256 f5fb3e341fcaab5f650f81945ee2568393b0488757a20f8fa76599affe07e742

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp39-cp39-win_arm64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp39-cp39-win_arm64.whl
  • Upload date:
  • Size: 530.0 kB
  • Tags: CPython 3.9, Windows ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp39-cp39-win_arm64.whl
Algorithm Hash digest
SHA256 44fcb07bc204d69dd27deb83e61a800897da52b364e6d7b5c74457651beb60e3
MD5 0601f0fbfde69f2011ceb1b6bde0e505
BLAKE2b-256 48c5f68b1928f0a780de6fe74ad1d6f102004a0ea68be7d1a047932df353294f

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 641.6 kB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 1e4460ac1b067d868759d84c821dfee2deab8615d2a6db1731400f46e14aed69
MD5 2ed9731fd823bc97da0b85b7673ccb25
BLAKE2b-256 7fc613a8863c7f5624724df6ea15dc4601ac2d47782b0eb5b72a272a9594fd2b

See more details on using hashes here.

File details

Details for the file winloop-0.6.3-cp38-cp38-win_amd64.whl.

File metadata

  • Download URL: winloop-0.6.3-cp38-cp38-win_amd64.whl
  • Upload date:
  • Size: 645.9 kB
  • Tags: CPython 3.8, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for winloop-0.6.3-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 723e65d134cbef1fd494e0197faa7036373509425357697c92dac225063d7327
MD5 90ca736ef2c04ff1147dcc0df8b92be1
BLAKE2b-256 441736d9a330c15eed39287489c606916a99877d9343e33cb28e19fd1a3244a7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page