Thiago Rodrigues
Software architect, director, speaker and community leader.
por Thiago Rodrigues (xthiago)
THIAGO RODRIGUES (xthiago)
UPX TECHNOLOGIES
https://xthiago.com
+ de uma década
evangelista
UEMG
Sistemas de Informação
Diretor de Desenvolvimento
SOCIAL HUB
Se não conseguir, OK
Os softwares que capturam tais informações são conhecidos como PROFILER
4.500 COMENTÁRIOS
Symfony/Demo com:
Docker
FROM upxlabs/php-fpm:latest
RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \
&& curl -A "Docker" -o /tmp/blackfire-probe.tar.gz \-D - -L -s \
https://blackfire.io/api/v1/releases/probe/php/alpine/amd64/$version \
&& tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp \
&& mv /tmp/blackfire-*.so \
$(php -r "echo ini_get('extension_dir');")/blackfire.so && printf \
"extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" \
> $PHP_INI_DIR/conf.d/blackfire.ini
Dockerfile
version: "2"
services:
phpfpm:
build:
context: ./docker/phpfpm
dockerfile: Dockerfile
volumes:
- ./docker/phpfpm/php.ini:/usr/local/etc/php/php.ini
- ./symfony-demo/:/var/www/app/
links:
- blackfire
blackfire:
image: blackfire/blackfire
environment:
BLACKFIRE_CLIENT_ID: 'XXXX'
BLACKFIRE_CLIENT_TOKEN: 'XXXX'
BLACKFIRE_SERVER_ID: 'XXXX'
BLACKFIRE_SERVER_TOKEN: 'XXXX'
nginx:
image: nginx:1.13.8-alpine
ports:
- "8000:80"
volumes:
- ./docker/nginx/vhost.conf:/etc/nginx/conf.d/default.conf
links:
- phpfpm
docker-compose.yml
GET http://app.localhost:8000/index.php/pt_BR/blog/comments/export
comment_id, comment_content, comment_published_at, comment_title
4000, Adorei! [..], 2018-03-04 23:55:15, Palestra
4050, Muito bom! [..], 2018-03-04 23:55:15, PHP Experience
4100, Quero ouvir: PHP! [..], 2018-03-04 23:55:15, PHP
// +4.500 linhas
class Comment {
/**
* @var int
*/
private $id;
/**
* @var Post
*/
private $post;
/**
* @var string
*/
private $content;
/**
* @var \DateTime
*/
private $publishedAt;
}
class Post {
/**
* @var int
*/
private $id;
/**
* @var Comment[]
*/
private $comments;
// outros campos
}
class BlogController extends AbstractController
{
public function commentsExport(CommentRepository $commentRepo): Response {
$comments = $commentRepo->findComments();
$data = "";
foreach ($comments as $comment) {
$data .= sprintf(
"%s,%s,%s,%s\n",
$comment->getId(),
$comment->getContent(),
$comment->getPublishedAt()->format('Y-m-d H:i:s'),
$comment->getPost()->getTitle()
);
}
$response = new Response($data);
$response->headers->set('Content-Type', 'application/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="file.csv"');
return $response;
}
class CommentRepository extends ServiceEntityRepository
{
public function findComments(): array
{
$query = $this->getEntityManager()
->createQuery('
SELECT c
FROM App:Comment c
ORDER BY c.publishedAt DESC
')
;
return $query->getResult();
}
2s em classe de Debug? 😠
Autoloader procurando classes do sistemas de arquivos
# Variáveis de ambiente definidas para produção
APP_ENV=prod
APP_DEBUG=0
# Cria autoloader otimizado para prod:
composer dump-autoload --classmap-authoritative
# Limpa e aquece o cache:
php bin/console cache:clear --env=dev --no-debug --no-warmup
php bin/console cache:warmup --env=dev
45% do tempo na query? 🤔
class CommentRepository extends ServiceEntityRepository
{
public function findComments(): array
{
$query = $this->getEntityManager()
->createQuery('
SELECT c
FROM App:Comment c
INNER JOIN c.post p
ORDER BY c.publishedAt DESC
')
;
return $query->getResult();
}
41% do tempo populando objetos? 🤔
Comparado com V2
class CommentRepository extends ServiceEntityRepository {
public function findComments(): array {
$query = $this->getEntityManager()->createQuery('
SELECT c.id, c.content, c.publishedAt, p.title
FROM App:Comment [continuação...]
');
// resto do método ...
}}
class BlogController extends AbstractController {
public function commentsExport(CommentRepository $commentRepo): Response {
// ...
foreach ($comments as $comment) {
$data .= sprintf(
"%s,%s,%s,%s\n",
$comment['id'],
$comment['content'],
$comment['publishedAt']->format('Y-m-d H:i:s'),
$comment['title']
);
}
// ...
}}
Em termos de velocidade, OK. Mas esse consumo de RAM ai hein? 🤔
Comparado com V1
Comparado com V3
class CommentRepository extends ServiceEntityRepository {
public function findComments(): iterable {
// montagem da query ...
return $query->iterate();
}}
Foi reduzido o consumo de memória.
E se retornarmos um stream?
Comparado com V4
class BlogController extends AbstractController {
public function commentsExport(CommentRepository $commentRepo): Response {
$comments = $commentRepo->findComments();
$response = new StreamedResponse();
$response->setCallback(function() use (&$comments) {
foreach ($comments as $comment) {
$handler = fopen('php://output', 'r+');
$comment = array_shift($comment);
fputs(
$handler,
sprintf(
"%s,%s,%s,%s\n",
$comment['id'],
$comment['content'],
$comment['publishedAt']->format('Y-m-d H:i:s'),
$comment['title']
)
);
}
});
return $response;
}}
E esse hydrate do Doctrine ai? Quase 25%.
Comparado com V5
Comparado com V1
class CommentRepository extends ServiceEntityRepository {
public function findComments(): iterable
{
$connection = $this->getEntityManager()->getConnection();
$sql = <<<EOF
SELECT
c.id, c.content, c.published_at, p.title
FROM symfony_demo_comment c
INNER JOIN symfony_demo_post p ON c.post_id = p.id
ORDER BY c.published_at DESC
EOF;
$stmt = $connection->prepare($sql);
$stmt->execute();
return $stmt->getIterator();
}
}
Comparado com V6:
Comparado com V1:
(slides já disponíveis na URL acima)
By Thiago Rodrigues
A velocidade de carregamento é um dos fatores primordiais na experiência dos usuários em aplicações Web. Sites e apps lentos frustram seus usuários, convertem menos e causam abandonos. Nessa mesma linha, algoritmos ineficientes geram custos maiores e podem até inviabilizar negócios. Muitos desenvolvedores não sabem identificar e como tratar quando tais sintomas se manifestam. Outros pecam pelo excesso, gastando recursos valiosos em otimizações precoces, pouco eficientes, que prejudicam a legibilidade do código e atrasam as entregas. Profiling é uma técnica usada para identificar gargalos e descobrir oportunidades de otimização. Essa palestra expõe uma abordagem eficiente para tratar problemas de otimização utilizando profiling, o momento e local ideal para aplicá-la e apresenta ferramentas que auxiliam neste processo.