Skip to main content
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 appreciated 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.

Metadata

Release files for winloop 0.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for winloop 0.8.0
File Size Uploaded
winloop-0.8.0.tar.gz 2.8 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for winloop 0.8.0
File
winloop-0.8.0-cp314-cp314t-win_arm64.whl CPython 3.14 CPython 3.14 free-threading Windows ARM64 Details
winloop-0.8.0-cp314-cp314t-win_amd64.whl CPython 3.14 CPython 3.14 free-threading Windows x86-64 Details
winloop-0.8.0-cp314-cp314-win_arm64.whl CPython 3.14 CPython 3.14 Windows ARM64 Details
winloop-0.8.0-cp314-cp314-win_amd64.whl CPython 3.14 CPython 3.14 Windows x86-64 Details
winloop-0.8.0-cp313-cp313-win_arm64.whl CPython 3.13 CPython 3.13 Windows ARM64 Details
winloop-0.8.0-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details
winloop-0.8.0-cp312-cp312-win_arm64.whl CPython 3.12 CPython 3.12 Windows ARM64 Details
winloop-0.8.0-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
winloop-0.8.0-cp311-cp311-win_arm64.whl CPython 3.11 CPython 3.11 Windows ARM64 Details
winloop-0.8.0-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
winloop-0.8.0-cp310-cp310-win_arm64.whl CPython 3.10 CPython 3.10 Windows ARM64 Details
winloop-0.8.0-cp310-cp310-win_amd64.whl CPython 3.10 CPython 3.10 Windows x86-64 Details
winloop-0.8.0-cp39-cp39-win_arm64.whl CPython 3.9 CPython 3.9 Windows ARM64 Details
winloop-0.8.0-cp39-cp39-win_amd64.whl CPython 3.9 CPython 3.9 Windows x86-64 Details

Total release size: 12.0 MB

Release files / winloop-0.8.0.tar.gz

Download URL winloop-0.8.0.tar.gz
Size 2.8 MB
Tags Source
SHA-256 checksum
How to use checksums
5a34605a72df5416279e89193688de0efb9e541c99e65923abcf0d7ff788510a
BLAKE2b-256 checksum
How to use checksums
558cc9af1d80e8680be97127b2429b03ecd2030e90ede8ab252a218db154bcd3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp314-cp314t-win_arm64.whl

Download URL winloop-0.8.0-cp314-cp314t-win_arm64.whl
Size 665.2 kB
Tags CPython 3.14 CPython 3.14 free-threading Windows ARM64
SHA-256 checksum
How to use checksums
52edcce751707cd0819a38a03e829a44e6a9ab3cac0b3e8cfd77cc1bfa9eff72
BLAKE2b-256 checksum
How to use checksums
8d2278f2dd4650f5017f24dc8c5aee05fd56c92a06725c39a12b2a8a53ac85c5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp314-cp314t-win_amd64.whl

Download URL winloop-0.8.0-cp314-cp314t-win_amd64.whl
Size 764.4 kB
Tags CPython 3.14 CPython 3.14 free-threading Windows x86-64
SHA-256 checksum
How to use checksums
9f902a4d5a43b8d46e15ddf2709180f790bdf1fc5515192bc799a087b0e72fac
BLAKE2b-256 checksum
How to use checksums
f363ca686d02d594986ab56fce4cdaf8308636f4c1f4a3fd6d2d4f3c0dcf92d1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp314-cp314-win_arm64.whl

Download URL winloop-0.8.0-cp314-cp314-win_arm64.whl
Size 617.0 kB
Tags CPython 3.14 Windows ARM64
SHA-256 checksum
How to use checksums
cd36320e519d4666a5b26af0b6bbda2384ca337f4d755353e2d0447d0893d795
BLAKE2b-256 checksum
How to use checksums
28f3fb43f4372167116b8a02e4f9695abde48e37879ee2d761322dcce9dd3efc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp314-cp314-win_amd64.whl

Download URL winloop-0.8.0-cp314-cp314-win_amd64.whl
Size 708.2 kB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
ad10c1320bec79fb41a5626ecd5d6c0fc00f2676aadeababf327ac4b07e42471
BLAKE2b-256 checksum
How to use checksums
f4dbcb60343c78ff06f7beaea199ca3336f68cd0a59a4eeb9cf501de27238bcb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp313-cp313-win_arm64.whl

Download URL winloop-0.8.0-cp313-cp313-win_arm64.whl
Size 604.7 kB
Tags CPython 3.13 Windows ARM64
SHA-256 checksum
How to use checksums
b978496a3114e238e9f5adf87d7e31d59e1119ce53f7073771caf2a88873bf1c
BLAKE2b-256 checksum
How to use checksums
6c9042c89d57f288a353be3d021bc3b9096074ec3b5e053510bf37d729974d42
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp313-cp313-win_amd64.whl

Download URL winloop-0.8.0-cp313-cp313-win_amd64.whl
Size 698.6 kB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
12ac56b01e266172afb4c5c4599c03f2ab7654d498570b7666c12cd9be2aa19c
BLAKE2b-256 checksum
How to use checksums
3c724f77a4d1d73fc0218a28130808841480ec8e02a756f6686a5650da70c853
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp312-cp312-win_arm64.whl

Download URL winloop-0.8.0-cp312-cp312-win_arm64.whl
Size 604.5 kB
Tags CPython 3.12 Windows ARM64
SHA-256 checksum
How to use checksums
2b200e3d4d833b82693c6038ddbaed72dd12e5517008c08042615545c47b4595
BLAKE2b-256 checksum
How to use checksums
9a1054c71ab926840a2da5b6de6fd669e874b49eac97d496b0d27c9c57fd73ed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp312-cp312-win_amd64.whl

Download URL winloop-0.8.0-cp312-cp312-win_amd64.whl
Size 699.3 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
10e0b32d206274435dc6f1f4542f6f6c47287e45c661c510ab782cecb52d65a3
BLAKE2b-256 checksum
How to use checksums
5133b28cd18a260800726e531575607ed3f2692993deb54e5fd05b129d0bd58c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp311-cp311-win_arm64.whl

Download URL winloop-0.8.0-cp311-cp311-win_arm64.whl
Size 607.2 kB
Tags CPython 3.11 Windows ARM64
SHA-256 checksum
How to use checksums
0676af99c928fe693624fc13e402ee8b94fdb8ec41115cede2f8a04075f9366e
BLAKE2b-256 checksum
How to use checksums
76e1af6e25cf53435eb69f7af17e3793efadf13092b55b188397143636d36a7a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp311-cp311-win_amd64.whl

Download URL winloop-0.8.0-cp311-cp311-win_amd64.whl
Size 677.2 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
31208cf3a8cff0cb77998ed90cda03cf264e96e083d1c1a0ebdf3a58a1e9fce3
BLAKE2b-256 checksum
How to use checksums
03daf196e036bed38b6d32f1a8af557c1535b486807add6f4c2144d4832b8bab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp310-cp310-win_arm64.whl

Download URL winloop-0.8.0-cp310-cp310-win_arm64.whl
Size 604.2 kB
Tags CPython 3.10 Windows ARM64
SHA-256 checksum
How to use checksums
4125b76ac55b9a7026d0cc35a2e873a34ed4e981a2d221b714d786a313ecb618
BLAKE2b-256 checksum
How to use checksums
f86c0cc635f9c3aa7e19a9d7391f85ae1ecd176e5ce75c1ed76ecc90eff4cc21
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp310-cp310-win_amd64.whl

Download URL winloop-0.8.0-cp310-cp310-win_amd64.whl
Size 669.4 kB
Tags CPython 3.10 Windows x86-64
SHA-256 checksum
How to use checksums
b3945303e5c1bde246f4910be7db756d7bea18fc610cd64d761bb67d94261724
BLAKE2b-256 checksum
How to use checksums
3e996fb0b4ada0f712d0c051e684f555dbd133f25e0524c470e9bed5c07aff62
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp39-cp39-win_arm64.whl

Download URL winloop-0.8.0-cp39-cp39-win_arm64.whl
Size 604.7 kB
Tags CPython 3.9 Windows ARM64
SHA-256 checksum
How to use checksums
cfddfa7f423a4ab0c8ea579cccccb14b2ed9528e540daac37b971c22786dcc02
BLAKE2b-256 checksum
How to use checksums
8a14c644e8a5ffae21369966d39adffe1b266cc04828c426503ab6a69b8d55df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.8.0-cp39-cp39-win_amd64.whl

Download URL winloop-0.8.0-cp39-cp39-win_amd64.whl
Size 670.5 kB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
3a04195b9849b53028c32c7782e2c06044f469bee9b1e6c4010de6258474a836
BLAKE2b-256 checksum
How to use checksums
c1b773a2a03726f7887eb34b529932677d3475f719d50b070ca3f2934ae41385
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.8.0 This release

15 release files

0.7.2

15 release files

0.7.0

15 release files

0.6.4

15 release files

0.6.3

16 release files

0.6.2

16 release files

0.6.0

22 release files

0.5.0

22 release files

0.4.2

22 release files

0.4.1

22 release files

0.3.1

22 release files

0.3.0

22 release files

0.2.2

22 release files

0.2.1

22 release files

0.2.0

16 release files

0.1.8

7 release files

0.1.7

7 release files

0.1.6

6 release files

0.1.5

6 release files

0.1.4

6 release files

0.1.3

5 release files

0.1.2

5 release files

0.1.1

5 release files

0.1.0

5 release files

0.0.9

5 release files

0.0.8

5 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

1 release file

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page