Skip to content

Async requests #98

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
MiWeiss opened this issue May 27, 2022 · 17 comments · Fixed by #146
Closed

Async requests #98

MiWeiss opened this issue May 27, 2022 · 17 comments · Fixed by #146
Labels
enhancement New feature or request

Comments

@MiWeiss
Copy link
Contributor

MiWeiss commented May 27, 2022

Exposing async interfaces would allow using this library in a much more modern, performant, and scalable way.

Would be great if the maintainers could mention if they plan to add async methods in the future (i.e., allow for nonblocking api usage). Even specifying explicitly that this won't be added would be great, as it allows 3rd parties to release their own fork or wrapper, without the risk of being obsolete just moments later :-)

@ArtemBernatskyy
Copy link

Nice ignore, ggwp

@hallacy hallacy added the enhancement New feature or request label Jul 28, 2022
@hallacy
Copy link
Collaborator

hallacy commented Jul 28, 2022

Hi @MiWeiss! Thanks for the issue.

Adding async support is on the roadmap, though we aren't committing to a timeline for when it'll be released. While I generally agree that an async interface would be good, can you tell me a little more about the performance improvement you'd expect to see if we added it? That'll help give us a sense about how to prioritize it.

@MiWeiss
Copy link
Contributor Author

MiWeiss commented Jul 28, 2022

Hi @hallacy

Thanks for your answer.

I am not sure how to understand your question (e.g., are you asking about the technical reasons or use cases?), so please excuse if my answer misses its target...

Quick motivation:
Async requests makes it very easy to perform other tasks while waiting for the response to a request to OpenAI. If the "other tasks" are also io/network bound (e.g. more requests to OpenAI 😄), I'm likely also running them in an async way, such that I can combine the waiting time (as such, the time I wait is approx. equal to the time the slowest task takes). This is naturally much faster than doing all the waiting sequentially.

And yes, much of that could be done using threads, but there are various disadvantages (especially for i/o bound operations) to using threading over asyncio. See e.g. this great comment.

See also these fastapi docs providing a detailed, yet simple and intuitive motivation for using async requests.

Does this answer your question?

Also, IMHO
It may be nontrivial to change the library such that both async and synchronous requests are supported, both from an implementation perspective (session handling, api design, etc.) and regarding documentation (every snippet can be async or sync)? It might be easier to offer async-openai as a standalone library. That's just my five cents and I am happy to be proven wrong, though.

@hallacy
Copy link
Collaborator

hallacy commented Jul 28, 2022

It does! Thank you for the writeup. That comment you linked to was particularly helpful.

I think I agree with that opinion about non-triviality. I can't commit to a timeline, but I'll make a point of bringing this up to the team soon

@lucasgadams
Copy link

lucasgadams commented Oct 5, 2022

This is badly needed! Having to make concurrent requests using threading is not good for modern python. And it's honestly better to start on it earlier, because the whole library will need to be upgraded. Or of course can make a new library for it. The nodejs openai library is naturally async which is a big advantage. In the meantime, asyncifying function calls with a threadpool seems to work well for me https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor.

@Andrew-Chen-Wang
Copy link
Contributor

Andrew-Chen-Wang commented Dec 4, 2022

Happy to commit to this. Based on previous experience with Redis and Django, a standalone package isn't needed, and this package would only need to include aiohttp as a dependency. Elasticsearch has async dependencies as optional, but in my opinion it doesn't need to be for this repository. Should be done tomorrow. (In the meantime, you can use asgiref and use sync_to_async)

@Andrew-Chen-Wang
Copy link
Contributor

Andrew-Chen-Wang commented Dec 6, 2022

#146 resolves this issue. Please go test it, thanks. Usage (notice the a prefix, used in CPython lib, Django, and other libs):

import openai

openai.api_key = "sk-..."

async def main():
    await openai.Completion.acreate(prompt="This is a test", engine="text-ada-001")

In the meantime, you can use asgiref (notice the lack of the a prefix):

import openai
from asgiref.sync import sync_to_async

openai.api_key = "sk-..."

async def main():
    await sync_to_async(openai.Completion.create)(prompt="Test is a test", engine="text-ada-001")

@itayzit
Copy link

itayzit commented Dec 17, 2022

in the meantime, you can also use this light-weight client i wrote (it's using httpx)
https://pypi.org/project/openai-async/

something like:

pip install openai-async

and then:

import openai_async

response = await openai_async.complete(
    "<API KEY>",
    timeout=2,
    payload={
        "model": "text-davinci-003",
        "prompt": "Correct this sentence: Me like you.",
        "temperature": 0.7,
    },
)
print(response.json()["choices"][0]["text"].strip())
>>> "I like you."

@danbf
Copy link

danbf commented Feb 3, 2023

@itayzit @MiWeiss any luck with this on a high concurrency implementation? i'm trying this but not getting the rates i'm hoping for.

@Andrew-Chen-Wang
Copy link
Contributor

@danbf Recommend you also manually control the aiohttp session:

import openai
from aiohttp import ClientSession

openai.aiosession.set(ClientSession())
# At the end of your program, close the http session
await openai.aiosession.get().close()

@MiWeiss
Copy link
Contributor Author

MiWeiss commented Feb 4, 2023

@danbf also note that OpenAI has rate limits in place: see here

@danbf
Copy link

danbf commented Feb 4, 2023

thanks @Andrew-Chen-Wang and @MiWeiss going to use that code hint and yup, was aware of the OpenAI rate limit.

@danbf
Copy link

danbf commented Feb 6, 2023

@Andrew-Chen-Wang @MiWeiss any ideas what to set TCPConnector(limit=XXX) to maximize throughput?

@lucasgadams
Copy link

You could try setting it to 0 for no limit. But honestly I very much doubt you can query openai with much more than 100 connections and not hit one of their quota limits.

@jonra1993
Copy link

jonra1993 commented Apr 13, 2023

It can be done also using asyncer

import openai

openai.api_key = settings.OPENAI_API_KEY

response = await asyncify(openai.ChatCompletion.create)(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "system", "content": "You are a helpful help desk assistant."},
        {"role": "user", "content": "Which is the capital of Ecuador?"},
        {
            "role": "assistant",
            "content": "The capital of Ecuador is Quito.",
        },
        {"role": "user", "content": "Responde lo mismo pero en español"},
    ],
)
print("response", response)

@vedantroy
Copy link

@Andrew-Chen-Wang -- would there be any disadvantage of using your PR over asyncer or vice-versa?

@Andrew-Chen-Wang
Copy link
Contributor

Andrew-Chen-Wang commented May 11, 2023

I would go with whatever openai-python has (ie my PR) since there are constant improvements to the repo, it's the official one, and all the examples online utilize this package. Performance is negligible for this repo since latency is the largest performance hindrance. It also seems easier to just import once (openai) and not twice (with asyncify)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants