<div dir="ltr"><div class="markdown-here-wrapper" style><p style="margin:1.2em 0px!important">Since there’s already a single-threaded eventloop running (tornado), the easiest way to ensure that actions in threads are properly serialized is to hand them off via <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248)">IOLoop.add_callback</code>. This has the advantage over the mutexes-everywhere approach that there isn’t anything to do in the vanilla single-threaded case.</p>
<p style="margin:1.2em 0px!important">Where to put this serialization is a bit of an open question. The simplest place to do it is on Session itself, since it would be always correct, but Session isn’t always used in the context of an IOLoop, so to do it at that level would require the most general, and thus most costly, approach (mutex on every send/recv). We could add a <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248)">send</code> method on Kernel that does any threading checks outside of Session, assuming that tornado is involved, which is always True when there’s a Kernel, unlike for Session.</p>
<p style="margin:1.2em 0px!important">A mockup of threadsafe send in a tornado context:</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="hljs language-python" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-radius:3px;display:inline;background-color:rgb(248,248,248);white-space:pre;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important;display:block;overflow-x:auto;padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248)"><span class="hljs-function"><span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">def</span> <span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">threadsafe_send</span><span class="hljs-params">(*args, **kwargs)</span>:</span>
    <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">if</span> <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">not</span> in_main_thread:
        <span class="hljs-comment" style="color:rgb(153,153,136);font-style:italic"># can't touch zmq sockets except from main thread</span>
        <span class="hljs-comment" style="color:rgb(153,153,136);font-style:italic"># call me again ASAP from the main thread</span>
        io_loop.add_callback(threadsafe_send, *args, **kwargs)

        <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">return</span>
    actually_send()
</code></pre>
<p style="margin:1.2em 0px!important">The advantage of this over a mutex is that there’s no lock to grab in the 99% case where it is actually called from the main thread.</p>
<p style="margin:1.2em 0px!important">The issue of mixed-up messages is actually a slightly separate from libzmq sockets themselves not being threadsafe. This is additional thread-unsafety provided by pyzmq’s send/recv_multipart, which was allowed because the underlying C socket is also not threadsafe. Making pyzmq itself threadsafe was considered (implemented, even), but it’s easy enough to do this at the application level that pyzmq doesn’t provided it for performance reasons.</p>
<p style="margin:1.2em 0px!important">-MinRK</p>
<div title="MDH:PGRpdiBjbGFzcz0iZ21haWxfZXh0cmEiPlNpbmNlIHRoZXJlJ3MgYWxyZWFkeSBhIHNpbmdsZS10
aHJlYWRlZCBldmVudGxvb3AgcnVubmluZyAodG9ybmFkbyksIHRoZSBlYXNpZXN0IHdheSB0byBl
bnN1cmUgdGhhdCBhY3Rpb25zIGluIHRocmVhZHMgYXJlIHByb3Blcmx5IHNlcmlhbGl6ZWQgaXMg
dG8gaGFuZCB0aGVtIG9mZiB2aWEgYElPTG9vcC5hZGRfY2FsbGJhY2tgLiBUaGlzIGhhcyB0aGUg
YWR2YW50YWdlIG92ZXIgdGhlIG11dGV4ZXMtZXZlcnl3aGVyZSBhcHByb2FjaCB0aGF0IHRoZXJl
IGlzbid0IGFueXRoaW5nIHRvIGRvIGluIHRoZSB2YW5pbGxhIHNpbmdsZS10aHJlYWRlZCBjYXNl
LjwvZGl2PjxkaXYgY2xhc3M9ImdtYWlsX2V4dHJhIj48YnI+PC9kaXY+PGRpdiBjbGFzcz0iZ21h
aWxfZXh0cmEiPldoZXJlIHRvIHB1dCB0aGlzIHNlcmlhbGl6YXRpb24gaXMgYSBiaXQgb2YgYW4g
b3BlbiBxdWVzdGlvbi4gVGhlIHNpbXBsZXN0IHBsYWNlIHRvIGRvIGl0IGlzIG9uIFNlc3Npb24g
aXRzZWxmLCBzaW5jZSBpdCB3b3VsZCBiZSBhbHdheXMgY29ycmVjdCwgYnV0IFNlc3Npb24gaXNu
J3QgYWx3YXlzIHVzZWQgaW4gdGhlIGNvbnRleHQgb2YgYW4gSU9Mb29wLCBzbyB0byBkbyBpdCBh
dCB0aGF0IGxldmVsIHdvdWxkIHJlcXVpcmUgdGhlIG1vc3QgZ2VuZXJhbCwgYW5kIHRodXMgbW9z
dCBjb3N0bHksIGFwcHJvYWNoIChtdXRleCBvbiBldmVyeSBzZW5kL3JlY3YpLiBXZSBjb3VsZCBh
ZGQgYSBgc2VuZGAgbWV0aG9kIG9uIEtlcm5lbCB0aGF0IGRvZXMgYW55IHRocmVhZGluZyBjaGVj
a3Mgb3V0c2lkZSBvZiBTZXNzaW9uLCBhc3N1bWluZyB0aGF0IHRvcm5hZG8gaXMgaW52b2x2ZWQs
IHdoaWNoIGlzIGFsd2F5cyBUcnVlIHdoZW4gdGhlcmUncyBhIEtlcm5lbCwgdW5saWtlIGZvciBT
ZXNzaW9uLjwvZGl2PjxkaXYgY2xhc3M9ImdtYWlsX2V4dHJhIj48YnI+PC9kaXY+PGRpdiBjbGFz
cz0iZ21haWxfZXh0cmEiPkEgbW9ja3VwIG9mIHRocmVhZHNhZmUgc2VuZCBpbiBhIHRvcm5hZG8g
Y29udGV4dDo8L2Rpdj48ZGl2IGNsYXNzPSJnbWFpbF9leHRyYSI+PGJyPjwvZGl2PjxkaXYgY2xh
c3M9ImdtYWlsX2V4dHJhIj5gYGBweXRob248L2Rpdj48ZGl2IGNsYXNzPSJnbWFpbF9leHRyYSI+
ZGVmIHRocmVhZHNhZmVfc2VuZCgqYXJncywgKiprd2FyZ3MpOjwvZGl2PjxkaXYgY2xhc3M9Imdt
YWlsX2V4dHJhIj4mbmJzcDsgJm5ic3A7IGlmIG5vdCBpbl9tYWluX3RocmVhZDo8L2Rpdj48ZGl2
IGNsYXNzPSJnbWFpbF9leHRyYSI+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgY2FuJ3Qg
dG91Y2ggem1xIHNvY2tldHMgZXhjZXB0IGZyb20gbWFpbiB0aHJlYWQ8L2Rpdj48ZGl2IGNsYXNz
PSJnbWFpbF9leHRyYSI+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgY2FsbCBtZSBhZ2Fp
biBBU0FQIGZyb20gdGhlIG1haW4gdGhyZWFkPC9kaXY+PGRpdiBjbGFzcz0iZ21haWxfZXh0cmEi
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBpb19sb29wLmFkZF9jYWxsYmFjayh0aHJlYWRz
YWZlX3NlbmQsICphcmdzLCAqKmt3YXJncyk8YnI+PC9kaXY+PGRpdiBjbGFzcz0iZ21haWxfZXh0
cmEiPiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyByZXR1cm48L2Rpdj48ZGl2IGNsYXNzPSJn
bWFpbF9leHRyYSI+Jm5ic3A7ICZuYnNwOyBhY3R1YWxseV9zZW5kKCk8L2Rpdj48ZGl2IGNsYXNz
PSJnbWFpbF9leHRyYSI+YGBgPC9kaXY+PGRpdiBjbGFzcz0iZ21haWxfZXh0cmEiPjxicj48L2Rp
dj48ZGl2IGNsYXNzPSJnbWFpbF9leHRyYSI+VGhlIGFkdmFudGFnZSBvZiB0aGlzIG92ZXIgYSBt
dXRleCBpcyB0aGF0IHRoZXJlJ3Mgbm8gbG9jayB0byBncmFiIGluIHRoZSA5OSUgY2FzZSB3aGVy
ZSBpdCBpcyBhY3R1YWxseSBjYWxsZWQgZnJvbSB0aGUgbWFpbiB0aHJlYWQuPC9kaXY+PGRpdiBj
bGFzcz0iZ21haWxfZXh0cmEiPjxicj48L2Rpdj48ZGl2IGNsYXNzPSJnbWFpbF9leHRyYSI+PGJy
PjwvZGl2PjxkaXYgY2xhc3M9ImdtYWlsX2V4dHJhIj5UaGUgaXNzdWUgb2YgbWl4ZWQtdXAgbWVz
c2FnZXMgaXMgYWN0dWFsbHkgYSBzbGlnaHRseSBzZXBhcmF0ZSBmcm9tIGxpYnptcSBzb2NrZXRz
IHRoZW1zZWx2ZXMgbm90IGJlaW5nIHRocmVhZHNhZmUuIFRoaXMgaXMgYWRkaXRpb25hbCB0aHJl
YWQtdW5zYWZldHkgcHJvdmlkZWQgYnkgcHl6bXEncyBzZW5kL3JlY3ZfbXVsdGlwYXJ0LCB3aGlj
aCB3YXMgYWxsb3dlZCBiZWNhdXNlIHRoZSB1bmRlcmx5aW5nIEMgc29ja2V0IGlzIGFsc28gbm90
IHRocmVhZHNhZmUuIE1ha2luZyBweXptcSBpdHNlbGYgdGhyZWFkc2FmZSB3YXMgY29uc2lkZXJl
ZCAoaW1wbGVtZW50ZWQsIGV2ZW4pLCBidXQgaXQncyBlYXN5IGVub3VnaCB0byBkbyB0aGlzIGF0
IHRoZSBhcHBsaWNhdGlvbiBsZXZlbCB0aGF0IHB5em1xIGRvZXNuJ3QgcHJvdmlkZWQgaXQgZm9y
IHBlcmZvcm1hbmNlIHJlYXNvbnMuPC9kaXY+PGRpdiBjbGFzcz0iZ21haWxfZXh0cmEiPjxicj48
L2Rpdj48ZGl2IGNsYXNzPSJnbWFpbF9leHRyYSI+LU1pblJLPC9kaXY+" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0">​</div></div></div>