Asynchronní dotazy v CURL

Školení, která pořádám

Extenze CURL nabízí podporu asynchronních požadavků. A podobně jako MySQLi neposkytuje zrovna přívětivé API. Vytvořil jsem proto knihovnu, která pokládání vícenásobných požadavků usnadní:

<?php
$http = new CurlAsync;

// položení požadavků
$http->test1("http://www.example.com/");
$http->test2("http://www.example.org/");

// získání odpovědí
print_r($http->test1());
print_r($http->test2());
?>

Knihovna je k dispozici na GitHubu.

Motivace pro asynchronní získávání dat je stejná jako u databáze: výkonnost. Stažení externích URL je obvykle časově náročné, takže hlavně když jich potřebujeme získat víc, vyplatí se to dělat na pozadí. Pokud očekáváme odpověď rychle, lze nastavit $http->timeout = .1.

Jakub Vrána, Řešení problému, 11.10.2010, diskuse: 12 (nové: 0)

Diskuse

optik:

Pardon, ale koukal jsem na to asi tak minutu, i na to předchozí, možná jsem něco přehlédl, ale tohle mi přijde jako fakt hnus, jquery určitě znáš když ho školíš, tak proč ne stejně jednoduše, např.

<?php
$async
= new CurlAsync;
$async->get("http://www.example.com/", function(){});
?>

místo té lambdy může být i 5.2 callback. Takhle to dělá jquery, node.js ... ta lambda z toho udělá teprve to pravé async. Odpadne také brzdící velehnus __call().

ikona Jakub Vrána OpenID:

Současné API byl jen takový pokus. Mám v plánu ho předělat, aby šel přidat interface. Ale callback předávat nebudu, způsob použití tomu neodpovídá. Na vrácená data potřebuješ počkat třeba v šabloně a použít je v určitém kontextu.

No a brát si jako protipříklad zrovna jQuery není úplně nejšťastnější vzhledem k existenci metod jako click(callback), které naváže událost, VS click(), které ji spustí. To je přesně stejná myšlenka.

alternate:

Pardon, ale celé PHP s javascriptem je pomalej velehnus:), doufám že se tento trend brzo změní, nerad bych se dožil doby, kde se video v prohlížeči bude renderovat sw javascriptovým kodekem:)

optik:

V pohodě, s php souhlas, s javascriptem ale ne, js vm udělaly za posledních pár let v optimalizaci proti PHP veleskok (abych zůstal u toho velesloví). Dokonce JITují už skoro všechny. Když se nepoužívá eval a ostatní brzdy, javascript bych řekl už na tom bude co se týče optimalizace mnohem lépe než php. A mě představa, že za pár let se bude psát většina aplikací v JS jak na serveru, tak na klientu vůbec nevadí.

ikona Jakub Vrána OpenID:

No tak ono i PHP udělalo veleskok dopředu, i když ne zrovna v oficiální větvi: http://php.vrana.cz/hiphop.php.

optik:

Ne, to není skok dopředu, ale stranou a to je pro majoritu uživatelů php k ničemu u JS engines je situace naprosto odlišná, tam ty vylepšení zasahují v postatě všechny.

kolator:

Když je CURL API nepřívětivé, proč nepoužít přítulnější nadstavbu, kterou ostatně PHP nabízí už dávno? Paralelní dotazy se tam dají poolovat snadno: http://cz.php.net/manual/en/class.httprequestpool.php

optik:

Jojo, škoda že Http PECL extenze u dávno není v core, myslím, že by mohla ušetřit spoustě frameworkům práci.

ikona Jakub Vrána OpenID:

Díky za tip, o tom jsem nevěděl.

starenka:

Jen tak zběžně jsem to prolít' na telefonu, kdyžtak mě po(p)opravte. Chapu to správně, že nejde přidávat vlastní "setopts"?

ikona Jakub Vrána OpenID:

Přesně tak, chtěl jsem co nejjednodušší API. Alternativou by bylo předávat výsledek curl_init($url).

Martin:

Z nějakého důvodu mi nic z výše uvedeného nefungovalo (IIS 7 ?). Nakonec se mi ale podařilo najít funkci, která to zvládá bez problémů. Zavolá stránku a nečeká na výsledek. Pokud na začátek volané stránky dáte     ignore_user_abort(true);, tak se vykoná.

<?php
   
// open a page and don't wait for the result
function curlPostAsync($url, $post_string = "")
{
    $parts = parse_url($url);

    $fp = fsockopen($parts['host'],
        isset($parts['port']) ? $parts['port'] : 80,
        $errno, $errstr, 30);

    $out = "POST ".$parts['path']." HTTP/1.1\r\n";
    $out.= "Host: ".$parts['host']."\r\n";
    $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
    $out.= "Content-Length: ".strlen($post_string)."\r\n";
    $out.= "Connection: Close\r\n\r\n";

    if ( isset($post_string))
        $out .= $post_string;

    fwrite($fp, $out);
    fclose($fp);
}
?>

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.