Significant performance hit when using async resolvers
@Cito y travaille déjà.
Depuis le 9/2/2023.
Évaluation
Cette issue n'a pas encore été évaluée.
Description
During development (Starlette + Ariadne) of our product I noticed significant performance degradation when GraphQL responses got significant long (1000+ entities in a list). I started profiling and drilling into the issue and I pinpointed it to async resolvers. Whenever a resolver is async and it is called a lot (100.000) you can see significant slowdowns 4x-7x, even if there is nothing async to it.
The question that I ended up with, is this a limitation of Python asyncio or how the results are gathered for async fields in graphql execute?
Any insight/help is greatly appreciated as we really need more performance and changing to sync is not really an option (nor is rewriting it to another language) 😭
import asyncio
from dataclasses import dataclass
from graphql import (
GraphQLField,
GraphQLList,
GraphQLObjectType,
GraphQLSchema,
GraphQLString,
graphql,
)
# On a MacBook Pro M1 Max this takes around 44 seconds in "async" case
# and "only" 7 seconds when async field is removed from the query
TOTAL_PEOPLE = 1000000
@dataclass
class Person:
firstName: str
lastName: str
def resolve_people(*_):
return [Person(f"Jane{i}", "Do") for i in range(0, TOTAL_PEOPLE)]
def resolve_fullname(person: Person, *_):
return f"{person.firstName} {person.lastName}"
async def async_resolve_fullname(person: Person, *_):
return f"{person.firstName} {person.lastName}"
PersonType = GraphQLObjectType(
"Person",
{
"firstName": GraphQLField(GraphQLString),
"lastName": GraphQLField(GraphQLString),
"fullName": GraphQLField(GraphQLString, resolve=resolve_fullname),
"asyncFullName": GraphQLField(GraphQLString, resolve=async_resolve_fullname),
},
)
schema = GraphQLSchema(
query=GraphQLObjectType(
name="RootQueryType",
fields={
"people": GraphQLField(GraphQLList(PersonType), resolve=resolve_people)
},
)
)
async def main():
result = await graphql(
schema,
"""#graphql
query {
people {
firstName
lastName
fullName
asyncFullName # THIS IS THE SLOW PART
}
}
""",
)
assert len(result.data["people"]) == TOTAL_PEOPLE
def run(callable, is_profile: bool = False):
if not is_profile:
return asyncio.run(callable())
import yappi
yappi.set_clock_type("WALL")
with yappi.run():
asyncio.run(callable())
func_stats = yappi.get_func_stats()
func_stats.save("callgrind.func_stats", "callgrind")
with open("func_stats.txt", "w") as file:
func_stats.print_all(
file,
{
# We increase the column widths significantly
0: ("name", 120),
1: ("ncall", 10),
2: ("tsub", 12),
3: ("ttot", 12),
4: ("tavg", 12),
},
)
if __name__ == "__main__":
run(main, is_profile=False)
Versions:
- macOS: 13.2
- python 3.11
- graphql-core 3.2.3
- yappi 1.4.0
- Langage dominant
- Python
- Étoiles
- 531
- Forks
- 147
- Métriques de merge des PR
- Aucune PR mergée en 30 j
Préparer son environnement
Nous n'avons pas encore vérifié les fichiers d'installation de ce projet. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de graphql-python/graphql-core
-
Difficulté 3/5 1-2 jours Accessibilité débutants 45/100
graphql-python/graphql-core#257 ·
-
Difficulté 3/5 1-2 jours Accessibilité débutants 35/100
graphql-python/graphql-core#223 · 1 commentaire ·
-
documentation good first issue
Difficulté 2/5 1-3 heures Accessibilité débutants 35/100
graphql-python/graphql-core#220 · 4 commentaires ·
-
help wanted investigate
Difficulté 4/5 3-5 jours Accessibilité débutants 35/100
graphql-python/graphql-core#217 · 8 commentaires ·
-
Difficulté 5/5 Plus d'une semaine Accessibilité débutants 35/100
graphql-python/graphql-core#216 · 11 commentaires ·
Toutes les issues de graphql-python/graphql-core
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 88/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
spec-kitty/spec-kitty#5319 ·
Les mainteneurs répondent en général sous 1 jour
-
backend::vllm diffusion multimodal
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
openai/openai-agents-python#5229 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
Les mainteneurs répondent en général sous 1 jour