<div dir="ltr"><div>To me it doesn't look like any specific imports are especially expensive, but there are a bunch of them, so they add up.</div><div><br></div><div>But, preliminary testing suggests that this technique works well. </div>
<div><br></div><div>I imported all the invariant modules into the current namespace and stored a reference to the current namespace, as you suggested:</div><div><br></div><div>(require mod1 mod2 ... modn)</div><div>(define original-ns (current-namespace))<br>
</div><div><br></div><div>Then, once inside the eval namespace, attached them all:</div><div><br></div><div><div>(map (ë(mod-name) (namespace-attach-module original-ns mod-name)) '(mod1 mod2 ... modn))</div></div><div>
<br></div><div>Now, instead of 7-8 seconds, each trip through eval takes 2-4 seconds. Probably more can be done, but that's already much better.</div><div><br></div><div><br></div>Matthew Butterick<div><br><div class="gmail_extra">
<br><br><div class="gmail_quote">On Mon, Oct 14, 2013 at 4:24 PM, Robby Findler <span dir="ltr"><<a href="mailto:robby@eecs.northwestern.edu" target="_blank">robby@eecs.northwestern.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote"><div class="im">On Mon, Oct 14, 2013 at 6:20 PM, Matthew Butterick <span dir="ltr"><<a href="mailto:mb.list.acct@gmail.com" target="_blank">mb.list.acct@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr">I reviewed the docs about the <a href="http://docs.racket-lang.org/reference/syntax-model.html?q=module%20registry#%28tech._module._registry%29" target="_blank">module registry</a>, but just so I understand the principle behind this technique — <div>
<br></div><div>When you call <span style="font-family:arial,sans-serif;font-size:12.727272033691406px">(namespace-attach-module orig-ns 'module-name), what you're saying to the new namespace is "if you need module-name, use the one that's already been imported into orig-ns". Is this right?</span></div>
<div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></span></div></div></blockquote><div><br></div></div><div>Right.</div><div class="im"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div dir="ltr"><div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"></span></div><div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px">And if so, do I improve performance by adding another (</span><span style="font-family:arial,sans-serif;font-size:12.727272033691406px">namespace-attach-module ...) declaration for each module that will never need to be reloaded in the eval namespace?</span></div>
<div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></span></div></div></blockquote><div><br></div></div><div>Right.</div><div class="im"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div dir="ltr"><div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"></span></div><div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px">BTW I tried your suggestion on the quasicode, and it was indeed faster. However, when I moved it back into the real code, there was no improvement — in fact, the real code became slower. Running the real code through profile suggests that most of the time is being spent traversing the imports (which is consistent with my observation that the complexity of the page itself doesn't count for much). So whatever I can do to avoid re-importing modules will probably be the winning technique.</span></div>
<div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></span></div></div></blockquote><div><br></div></div><div>Which module's imports, do you know?</div><span class=""><font color="#888888"><div>
<br></div><div>Robby</div></font></span><div><div class="h5"><div> </div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"></span></div>
<div>Thanks. <span style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br>
</span></div></div><div><div><div class="gmail_extra">
<br><br><div class="gmail_quote">On Mon, Oct 14, 2013 at 11:22 AM, Robby Findler <span dir="ltr"><<a href="mailto:robby@eecs.northwestern.edu" target="_blank">robby@eecs.northwestern.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div dir="ltr">Did you try using namespace-attach-module to attach 'racket and 'web-server/templates? Something like:<div><br></div><div><div> (define orig-ns (current-namespace))</div><div><div> (parameterize ([current-namespace (make-base-empty-namespace)]) </div>
</div><div> (namespace-attach-module orig-ns 'racket)</div><div> (namespace-attach-module orig-ns 'web-server/templates)</div><div><div> (namespace-require 'racket)</div><div> (eval `(begin </div>
<div> (require web-server/templates)</div>
<div> (require ,my-source-path-string)</div><div> (include-template ,my-template-path-string))</div><div> (current-namespace)))</div></div></div><div><br></div><div>But 7 seconds seems remarkably long (I see a speed up of about 50% for that function (with the my-source-path-string and my-template-path-string lines commented out): from 250 to 170 msec).</div>
<div><br></div><div>It may be that your .zo files or something are not up to date. So you may want to stick a 'raco make' somewhere in there to avoid recompiling your files every time and just recompile the ones that changed.</div>
<span><font color="#888888">
<div><br></div><div>Robby</div><div><br></div><div><br></div></font></span></div><div><div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Oct 14, 2013 at 1:14 PM, Matthew Butterick <span dir="ltr"><<a href="mailto:mb.list.acct@gmail.com" target="_blank">mb.list.acct@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div><div>At RacketCon I talked about my Pollen system for making web pages. Though I don't use the Racket webserver to provide live generation of web pages, I do use it to provide a kind of browser-assisted REPL for development. As I edit the project files, I want to reload the URL in the browser and see the changes (without restarting the webserver). </div>
<div><br></div><div>Moreover, since it's a development tool, it wants to be maximally dynamic. For instance, I might be editing source files containing page content, or the design templates (which might also contain Racket code), or supporting Racket libraries (e.g., CSS generators).</div>
<div><br></div><div>Jay has suggested that this can be done with eval. And indeed it can. Here's the quasicode I use:</div><div><br></div><div> (parameterize ([current-namespace (make-base-empty-namespace)]) </div><div>
(namespace-require 'racket)</div><div> (eval `(begin </div><div> (require web-server/templates)</div><div> (require ,my-source-path-string)</div><div> (include-template ,my-template-path-string)) </div>
<div> (current-namespace))))</div></div><div><br></div><div>This works great, with one wrinkle: it's the slowest operation in the whole system, taking about 7-8 secs to render each page. This is not a grave hardship, and certainly faster than restarting the web server. But I'd still be curious if I'm overlooking a better approach.</div>
<div><br></div><div>In general, the render time is fairly consistent regardless of what's in the page, which suggests to me that most of the expense comes from setting up the fresh namespace. I did try making a namespace separately and reusing it, but that didn't work (code wouldn't get reloaded). Is there a way to "clean" a namespace that's cheaper than setting up a new one?</div>
<div><br></div><div>Another option I considered is starting up another instance of Racket in a subprocess, but it would need to be made into a synchronous operation. Long drive for a short day at the beach, etc.</div><div>
<br></div><div>It's also possible that I'm running up against the irreducible cost of high-quality eval, in which case, I will accept it and move on.</div><span><font color="#888888"><div><br></div>
<div><br></div><div>Matthew Butterick<br></div></font></span><div><div>
<div><br></div><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Jun 6, 2013 at 7:36 PM, Greg Hendershott <span dir="ltr"><<a href="mailto:greghendershott@gmail.com" target="_blank">greghendershott@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Great timing! It's been on my short list to make my static blog<br>
generator more flexible. From<br>
<a href="http://docs.racket-lang.org/web-server/templates.html" target="_blank">http://docs.racket-lang.org/web-server/templates.html</a> I got the idea<br>
that it would be suitable only for static templates, but now I<br>
understand that's not the case. Today I made a topic branch using this<br>
approach that's working well, which I plan to merge after some testing<br>
and polishing.<br>
<br>
p.s. Maybe it's obvious, but because `include-template` uses<br>
`include-at/relative-to/reader`, it won't include a template if you<br>
give it a full path. Maybe there's a more-elegant way, but I found it<br>
worked to parameterize `current-directory` around the call to `eval`.<br>
<div><div><br>
<br>
On Wed, Jun 5, 2013 at 4:45 PM, Jay McCarthy <<a href="mailto:jay.mccarthy@gmail.com" target="_blank">jay.mccarthy@gmail.com</a>> wrote:<br>
> While it is supposed to be pithy, it is also serious.<br>
><br>
> When I wrote it, I imagine that people would do something like this:<br>
><br>
> #lang racket/base<br>
> (require web-server/templates)<br>
><br>
> (define (template-content t x)<br>
> (eval #`(let ([x #,x]) (include-template #,t))))<br>
><br>
> (template-content "t.txt" 5)<br>
> (template-content "t.txt" 6)<br>
><br>
> and trust that the template wouldn't include @(system "rm -fr /"). I<br>
> think that a simple eval works just fine for when you, the programmer,<br>
> want to change the content dynamic (although I'd say it is better to<br>
> use the web-server language so you can restart with the same<br>
> continuations, etc.)<br>
><br>
> Your solution is great for a template that a user provides, although<br>
> it has the hole that the template could call @include-template and<br>
> maybe find itself and go into a infinite loop, so it's not totally<br>
> "secure" unless you use a sandbox.<br>
><br>
> Jay<br>
><br>
> On Wed, Jun 5, 2013 at 1:53 PM, Joe Gibbs Politz <<a href="mailto:joe@cs.brown.edu" target="_blank">joe@cs.brown.edu</a>> wrote:<br>
>> I'm writing a web server in a #lang that doesn't support macros or<br>
>> syntactic abstraction. I would like to be able to use some sort of<br>
>> templating dynamically with bindings given by values, e.g.<br>
>><br>
>> template.render("page-with-hole-for-username.html", { username: "Joe" })<br>
>><br>
>> The FAQ (<a href="http://docs.racket-lang.org/web-server/faq.html#(part._.How_do_.I_use_templates__dynamically__)" target="_blank">http://docs.racket-lang.org/web-server/faq.html#(part._.How_do_.I_use_templates__dynamically__)</a>)<br>
>> in the documentation for templates ends with this pithy<br>
>> recommendation:<br>
>><br>
>> "If you insist on dynamicism, there is always eval."<br>
>><br>
>> I assume this isn't intended seriously, and instead to discourage what<br>
>> I'm asking about, but I'm unfortunately not seeing another way to<br>
>> write my program. The code at the end of this message seems like the<br>
>> best I can do while being relatively safe, but also like a dubious<br>
>> inclusion on a web server given the eval.<br>
>><br>
>> Is this the best I can hope for? Is there another collection I should<br>
>> be looking into? Any other recommendations?<br>
>><br>
>> Thanks!<br>
>> Joe P.<br>
>><br>
>><br>
>> #lang racket/base<br>
>><br>
>> (require<br>
>> web-server/templates)<br>
>><br>
>> (define (render-template filename dict)<br>
>> (define namespace-for-template (make-empty-namespace))<br>
>> (namespace-attach-module (current-namespace) 'web-server/templates<br>
>> namespace-for-template)<br>
>> (hash-map dict<br>
>> (lambda (key value)<br>
>> (define name-of-identifier (string->symbol key))<br>
>> (namespace-set-variable-value!<br>
>> name-of-identifier<br>
>> value<br>
>> #f<br>
>> namespace-for-template)))<br>
>> (parameterize [(current-namespace namespace-for-template)]<br>
>> (namespace-require 'web-server/templates))<br>
>> (define to-eval #`(include-template #,(datum->syntax<br>
>> #'render-template filename)))<br>
>> (eval to-eval namespace-for-template))<br>
>> ____________________<br>
>> Racket Users list:<br>
>> <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
><br>
><br>
><br>
> --<br>
> Jay McCarthy <<a href="mailto:jay@cs.byu.edu" target="_blank">jay@cs.byu.edu</a>><br>
> Assistant Professor / Brigham Young University<br>
> <a href="http://faculty.cs.byu.edu/~jay" target="_blank">http://faculty.cs.byu.edu/~jay</a><br>
><br>
> "The glory of God is Intelligence" - D&C 93<br>
> ____________________<br>
> Racket Users list:<br>
> <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
____________________<br>
Racket Users list:<br>
<a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
</div></div></blockquote></div><br></div></div></div></div>
<br>____________________<br>
Racket Users list:<br>
<a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
<br></blockquote></div><br></div>
</div></div></blockquote></div><br></div>
</div></div><br>____________________<br>
Racket Users list:<br>
<a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
<br></blockquote></div></div></div><br></div></div>
</blockquote></div><br></div></div></div>