Tuesday, August 10, 2010

Multithreaded Rails is generally better than Async Rails, and Rainbows is cooler than Node

Once upon a time Rails was single threaded and could only process one request at a time. This meant for each concurrent request you wanted to process with Rails, you needed to run an entirely separate Ruby VM instance. This was not a good state of affairs, especially in cases where your Rails application was blocking on I/O when talking to a database or other external service. An entire instance of your application sat there useless as it was waiting for I/O to complete.

The lack of multithreading in Rails would lead Ezra Zygmuntowicz to write Merb, a thread-safe web framework for Ruby which certainly borrowed conceptually from Rails and would go on to serve as the core for the upcoming Rails 3.0 release. In the meantime, the earlier Rails 2.x branch would get support for a thread safe mode as well. This meant that web applications written in Ruby could process multiple requests using a single VM instance: while one thread was blocking on a response from a database or other service, the web application could continue processing other requests in other threads.

Even better, while Ruby originally started out with a "green threads" implementation which executed threads in userspace and could not provide multicore concurrency, newer, more modern Ruby implementations emerged which provided true native multithreading. JRuby and IronRuby, implementations of Ruby on the JVM and .NET CLR respectively, provided truly concurrent native multithreading while still maintaining Ruby's original threading API. Rubinius, a clean-room implementation of a Ruby VM based on the Smalltalk 80 architecture, has started to take steps to remove its global lock and allow concurrent multithreading as well.

With a multithreaded web framework like Merb, recent versions of Rails 2.x, or Rails 3.0, in conjunction with a Ruby VM that supports concurrent multithreading, you now need to only run one VM instance with a copy of your web application and it can utilize all available CPU cores in a server, providing true concurrent computation of Ruby code. No longer do you need a "pack of Mongrels" to serve your Rails application. Instead, you can just run a single VM and it will utilize all available system resources. This has enormous benefits in terms of ease-of-deployment, monitoring, and memory usage.

Ruby on Rails has finally grown up and works just like web applications in other more popular languages. You can run just one copy of any Ruby VM that supports native multithreading and utilize all available server resources. Rails deployment is no longer a hack. It Just Works.

But Wait, Threads Are Bad, And Async Is The New Hotness!





Threads have typically had a rather mired reputation in the programming world.  Threads utilize shared state by default and don't exactly provide the greatest mechanisms for synchronizing bits of shared state.  They're a leaky abstraction, and without eternal vigilance on the part of an entire development team and an excellent understanding of what's happening when you use thread synchronization mechanisms, sharing state between threads is error-prone and often difficult to debug.

The "threads are bad" cargo cult has often lead people to pursue "interesting" solutions to various concurrency problems in order to avoid using threads.  Event-based concurrent I/O became an incredibly popular solution for writing network servers, an approach seen in libraries like libevent, libev, Python's Twisted, and in the Ruby world EventMachine and my own event library, Rev.  This scheme uses a callback-driven approach, often with a central reactor core, dispatching incoming I/O asynchronously to various handlers.  For strictly I/O-bound applications, things like static file web servers, proxies, and protocol transformers, this approach is pretty much the best game in town.

Node.js, a pretty awesome I/O layer for Google's V8 JavaScript interpreter, is something of the new hotness.  It's certainly opened up the evented I/O approach to a new audience, and for I/O-bound tasks it provides a way to script in a dynamic language while remaining quite fast.  But as others have noted, Node is a bit overhyped. If you write your server in Node, will it scale? It really depends on the exact nature of the problem.  I'll get into that in a bit.

Ilya Grigorik recently presented at RailsConf and OSCON about em-synchrony, a set of "drivers" for EventMachine which facilitate various types of network I/O which present a synchronous interface but use Fibers to perform I/O asynchronously in the background. He had some rather impressive things to share there, including Rails running on top of EventMachine, dispatching requests concurrently using fibers instead of threads.  This approach won't provide you the computational concurrency that truly multithreaded Rails as in JRuby and IronRuby (and Rubinius soon!), but it will provide you wicked fast I/O performance... at a price.

The New Contract



Programmers generally live in a synchronous world. We call functions which return values. That's the status quo. Some languages go so far as to make this the only possible option. Evented frameworks do not work like this. Evented frameworks turn the world upside down.  For example, in Ruby, where you might ordinarily write something like:

response = connection.request params

In async land, you first have to initiate the request:

begin_request params

Then define a callback in order to receive the response:

def on_response(response)
  ...
end

Rather than calling functions, you initiate side effects which will eventually call one of a number of callbacks.  Exceptions no longer work. The context is lost between callbacks; you always start from just your arguments and have to figure out exactly what you were up to before, which generally necessitates breaking anything complex down into a finite state machine, instead of say, an imperative list of I/O commands to perform. It's a very different approach from the status quo.

The em-synchrony approach promises to save you from this by wrapping up all that ugly callback driven stuff with Fibers. I've been down that road and I no longer recommend it.  In January 2008 I wrote Revactor, a Erlang-like implementation of the Actor Model for Ruby 1.9, using Fibers as the underlying concurrency primitive. It's the first case known to me of someone using this approach, and significantly more powerful than any of the other available frameworks. Where em-synchrony makes you write Fiber-specific code for each network driver, Revactor exposed an incomplete duck type of Ruby's own TCPSocket, which means that patching drivers becomes significantly easier as you don't need asynchronous drivers to begin with.

However, for the most part I stopped maintaining Revactor, largely because I began to think the entire approach is flawed. The problem is frameworks like Revactor and em-synchrony impose a new contract on you: evented I/O only! You aren't allowed to use anything that does any kind of blocking I/O in your system anywhere, or you will hang the entire event loop. This approach works great for something like Node.js, where the entire system was written from the ground-up to be asynchronous, in a language which has a heritage of being asynchronous to begin with.

Not so in Ruby. There are tons and tons of libraries that do synchronous I/O. If you choose to use async Rails, you can't use any library which hasn't specifically been patched with em-synchrony-like async-to-Fiber thunks. Since most libraries haven't been patched with this code, you're cutting yourself off from the overwhelming majority of I/O libraries available. This problem is compounded by the fact that the only type of applications which will benefit from the async approach more than the multithreaded approach are ones that do a lot of I/O.

This is a problem you have to be eternally vigilant about what libraries you use and make absolutely sure nothing ever blocks ever. Hmm, is this beginning to sound like it may actually be as problematic as threads? And one more thing: exceptions. Dealing with exceptions in an asynchronous environment is very difficult, since control is inverted and exceptions don't work in callback mode. Instead, for exceptions to work properly, all of the "Fibered" em-synchrony-like drivers must catch, pass along, and rethrow exceptions. This is left as an exercise to the driver writer.

Threads are Good


Threads are bad when they have to share data.  But when you have a web server handling multiple requests concurrently with threads, they really don't need to share any data at all.  When threads don't share any data, multithreading is completely transparent to the end user. There are a few gotchas in multithreaded Rails, such as some foibles with the initial code loading, but after you get multithreaded Rails going, you won't even notice the difference from using a single thread.  So what cases would Async Rails be better than multithreaded Rails for?  I/O bound cases. For many people the idea of an I/O bound application draws up the canonical Rails use case: a database-bound app.

"Most Rails apps are database bound!" says the Rails cargo cult, but in my experience, useful webapps do things.  That said, Async Rails will have its main benefits over multithreaded apps in scenarios where the application is primarily I/O bound, and a webapp which is little more than a proxy between a user and the database (your typical CRUD app) seems like an ideal use case.

What does the typical breakdown of time spent in various parts of your Rails app look like?  The conventional wisdom would say this:

But even this is deceiving, because models generally do things in addition to querying your database. So really, we need a breakdown of database access time.  Evented applications benefit from being bound on I/O with little computation, so for an Async Rails app this is the ideal use case:

Here our application does negligible computation in the models, views, and controllers, and instead spends all its time making database queries. This time can involve writing out requests, waiting while the database does its business, and consuming the response.

This picture is still a bit vague.  What exactly is going on during all that time spent doing database stuff?  Let's examine my own personal picture of a typical "read" case:



For non-trivial read cases, your app is probably spending a little bit of time doing I/O to make the REQuest, most of its time waiting for the database QueRY to do its magic, and then spending some time reading out the response.

But a key point here: your app is spending quite a bit of time doing nothing but waiting between the request and the response.  Async Rails doesn't benefit you here. It removes some of the overhead for using threads to manage an idle connection, but most kernels are pretty good about managing a lot of sleepy threads which are waiting to be awoken nowadays.

So even in this case, things aren't going to be much better over multithreaded apps, because your Rails app isn't actually spending a lot of time doing I/O, it's spending most of it's time waiting for the database to respond. However, let's examine a more typical use case of Rails:

Here our app is actually doing stuff! It's actually spending a significant amount of time computing, with some time spent doing I/O and a decent chunk spent just blocking until an external service responds. For this case, the multithreaded model benefits you best: all your existing Ruby tools will Just Work (provided they don't share state unsafely), and best of all, when running multithreaded on JRuby or IronRuby (or Rubinius soon!) you can run a single VM image, reduce RAM usage by sharing code between threads, and leverage the entire hardware stack in the way the CPU manufactures intended.

Why You Should Use JRuby

JRuby provides native multithreading along with one of the most compatible alternative Ruby implementations out there, lets you leverage the power of the JVM, which includes a great ecosystem of tools like VisualVM, a mature underlying implementation, some of the best performance available in the Ruby world, a diverse selection of garbage collectors, a significantly more mature ecosystem of available libraries (provided you want to wrap them via the pretty nifty Java Interface), and the potential to deploy your application without any native dependencies whatsoever. JRuby can also precompile all of your Ruby code into an obfuscated Java-like form, allowing you to ship enterprise versions to customers you're worried might steal your source code.  Best of all, when using JRuby you also get to use the incredibly badass database drivers available for JDBC, and get things like master/slave splits and failover handled completely transparently by JDBC. Truly concurrent request handling and awesome database drivers: on JRuby, it Just Works.

Why not use IronRuby? IronRuby also gives you native multithreading, but while JRuby has 3 full time developers working on it, IronRuby only has one. I don't want to say that IronRuby is dying, but in my opinion JRuby is a much better bet. Also, the JVM probably does a better job supporting the platforms of interest for running Rails applications, namely Linux.

Is Async Rails Useful? Kinda.

All that said, are there use cases Async Rails is good for? Sure! If your app is truly I/O bound, doing things like request proxying or a relatively minor amount of computation as compared to I/O (regex scraping comes to mind), Async Rails is awesome. So long as you don't "starve" the event loop doing too much computation, it could work out for you.

I'd really be curious about what kinds of Rails apps people are writing that are extremely I/O heavy though.  To me, I/O bound use cases are the sorts of things people look at using Node for. In those cases, I would definitely recommend you check out Rainbows instead of Async Rails or Node.  More on that later...

Why I Don't Like EventMachine, And Why You Should Use Rev (and Revactor) Instead

em-synchrony is built on EventMachine. EventMachine is a project I've been using and have contributed to since 2006. I really can't say I'm a fan. Rather than using Ruby's native I/O primitives, EventMachine reinvents everything. The reason for this is because its original author, Francis "Garbagecat" Cianfrocca, had his own libev(ent)-like library, called "EventMachine", which was written in C++. It did all of its own I/O internally, and rather than trying to map that onto Ruby I/O primitives, Francis just slapped a very poorly written Ruby API onto it, foregoing any compatibility with how Ruby does I/O. There's been a lot of work and refactoring since, but even so, it's not exactly the greatest codebase to work with.

While this may have been remedied since last I used EventMachine, a key part of the evented I/O contract is missing: a "write completion" callback indicating that EventMachine has emptied the write buffer for a particular connection. This has lead to many bugs in cases like when proxying from a fast writer to a slow reader, the entire message to be proxied is taken into memory. There are all sorts of special workarounds for common use cases, but that doesn't excuse this feature being missing from EventMachine's I/O model.

It's for these reasons that I wrote Rev, a Node-like evented I/O binding built on libev. Rev uses all of Ruby's own native I/O primitives, including Ruby's OpenSSL library. Rev sought to minimize the amount of native code in the implementation, with as much written in Ruby as possible. For this reason Rev is slower than EventMachine, however the only limiting factor is developer motivation to benchmark and rewrite the most important parts of Rev in C instead of Ruby. Rev was written from the ground up to perform well on Ruby 1.9, then subsequently backported to Ruby 1.8.

Rev implements a complete I/O contract including a write completion event which is used by Revactor's Revactor::TCP::Socket class to expose an incomplete duck type of Ruby's TCPSocket.  This should make monkeypatching existing libraries to use Revactor-style concurrency much easier.  Rather than doing all the em-synchrony-style Fiber thunking and exception shuffling yourself, it's solved once by Revactor::TCP::Socket, and you just pretend you're doing normal synchronous I/O.

Revactor comes with all sorts of goodies that people seem to ask for often. Its original application was for a web spider, which in early 2008 was sucking down and scanning regexes on over 30Mbps of data using four processes running on a quad core Xeon 2GHz. I'm sure it was, at the time, the fastest concurrent HTTP fetcher ever written in Ruby. Perhaps a bit poorly documented, this HTTP fetcher is part of the Revactor standard library, and exposes an easy-to-use synchronous API which scatters HTTP requests to a pool of actors and gathers them back to the caller, exposing simple callback-driven response handling. I hear people talking about how awesome that sort of thing is in Node, and I say to them: why not do it in Ruby?

Why Rainbows Is Cooler Than Node

Both Rev and Revactor-style concurrency are provided by Eric Wong's excellent Rainbows HTTP server. Rainbows lets you build apps which handle the same types of use cases as Node, except rather than having to write everything in upside async down world in JavaScript, using Revactor you can write normal synchronous Ruby code and have everything be evented underneath. Existing synchronous libraries for Ruby can be patched instead of rewritten or monkeypatched with gobs of Fiber/exception thunking methods.

Why write in asynchronous upside down world when you can write things synchronously? Why write in JavaScript when you can write in Ruby? Props to everyone who has worked on solutions to this problem,  and to Ilya for taking it to the mainstream, but in general, I think Rev and Revactor provide a better model for this sort of problem.

Why I Stopped Development on Rev and Revactor: Reia

A little over two years ago I practically stopped development on Rev and Revactor. Ever since discovering Erlang I thought of it as a language with great semantics but a very ugly face. I started making little text files prototyping a language with Ruby-like syntax that could be translated into Erlang. At the time I had outgrown my roots as an I/O obsessed programmer and got very interested in programming languages, how they work, and had a deep desire to make my own.

The result was Reia, a Ruby-like language which runs on top of the Erlang VM. I've been working on it for over two years and it's close to being ready! It's got blocks! It's got Ruby-like syntax! Everything is an (immutable) object! All of the core types are self-hosted in Reia. It's got a teensy standard library. Exceptions are kind of working. I'd say it's about 75% of the way to its initial release. Soon you'll be able to write CouchDB views with it.

Erlang's model provides the best compromise for writing apps which do a lot of I/O but also do a lot of computation as well. Erlang has an "evented" I/O server which talks to a worker pool, using a novel interpretation of the Actor model. Where the original Actor model was based on continuations and continuation passing, making it vulnerable to the same "stop the world" scenarios if anything blocks anywhere, Erlang chose to make its actors preemptive, more like threads but much faster because they run in userspace and don't need to make a lot of system calls.

Reia pursues Erlang's policy of immutable state systemwide. You cannot mutate state, period. This makes sharing state a lot easier, since you can share a piece of state knowing no other process can corrupt it. Erlang  uses a model very similar to Unix: shared-nothing processes which communicate by sending "messages" (or in the case of Unix, primitive text streams).  For more information on how Erlang is the evolution of the Unix model, check out my other blog post How To Properly Utilize Modern Computers, which spells out a lot of the same concepts I've discussed in this post more abstractly.  Proper utilization of modern computers is exactly what Reia seeks to do well.

Reia has been my labor of love for over two years. I'm sorry if Rev and Revactor have gone neglected, but it seems I may have just simply been ahead of my time with them, and only now is Ruby community interest in asynchronous programming piqued by things like Node and em-synchrony. I invite you to check out Rev, Revactor, and Reia, as well as fork them on Github and start contributing if you have any interest in doing advanced asynchronous programming on Ruby 1.9.

397 comments:

  1. I been working with erlang for some time now and following reia for some time now.

    I'm so excited about reia and can't wait to use it.

    ReplyDelete
  2. If your goal is to convince people, weak statements like 'most kernels are pretty good about managing a lot of sleepy threads' aren't going to help, especially if they're not backed by any evidence. Maybe you should run some benchmarks so instead of saying 'most kernels' you can say which kernels, and instead of 'pretty good' you can say exactly how good.

    ReplyDelete
  3. Numbers certainly speak louder than words, but in a post as long and rambly as this I really wasn't prepared to dig deep into modern thread performance.

    While I realize it's an appeal to authority, Varnish architect Poul-Henning Kamp has written one of the fastest HTTP caches available using a thread-per-connection model, and in the Varnish performance-tuning documentation claims "Having a number of idle threads is reasonably harmless."

    As for actual benchmarks, what's the use case? That's the point I've been trying to drive home in this entire post. Sure, I could make a synthetic benchmark comparing a threaded/blocking idle to an evented idle for large numbers of connections, but is that really useful?

    Performance benchmarks on a real-world Rails app would be interesting, but not really applicable to other people as everyone's app will vary.

    Bottom line, know your problem and choose your tools appropriately.

    ReplyDelete
  4. Tony, please ignore Kevin's trollish comment.

    I'm also very excited about Reia since I'm just getting started with Erlang.

    Although I must say it grew on me (like most, I used to find the syntax quite ugly) I've also been following Erlang's more "expressive" cousins, Efene, LFE and Reia.

    And though different in purpose, I think Reia is not only the more promising of the group, but also capable of being revolutionary (and a superior contender to Go =)). Nice job!

    ReplyDelete
  5. Awsome article ! Very good introduction on threads and async coding with constructive critics on existing tools.

    ReplyDelete
  6. This article could have been one line:

    "I like Ruby better than JS, so I'm gonna use this cool ruby thing rather than your cool JS thing."

    To which I can only respond:

    "I like JS better than Ruby, so I'm gonna use this cool JS thing rather than your cool Ruby thing."

    It's only preference/style. You're really not in any way criticizing the substance of nodejs, or pointing out where threads are architecturally *better* than event loops.

    ReplyDelete
  7. I'd be interested in another article clearly comparing strengths/weaknesses of evented programming vs synchronous programming for debugging situations and maintainability.

    The ideas in this article certainly ring true for the traditional procedural programmer, however, I wonder if this is the correct approach to abstract away events as deferred returns.

    ReplyDelete
  8. You know node is doing something right, because Rails guys are bashing it the same way that the Java guys were bashing rails five years ago.

    ReplyDelete
  9. Isaac,

    As you have correctly guessed, I prefer Ruby to JavaScript. However, one of the weird things about Node is that it has managed to attract a lot of people who would rather be programming Ruby to JavaScript. If you don't know/like Ruby but do like JavaScript, I can't criticize Node in that regard.

    But still, there's the "upside-down world" issue. Some people really like programming that way. For the majority of programmers, it's pretty foreign and hard to reason about. Having to decompose an otherwise procedural description of a protocol into FSMs to implement complex protocols still sucks. It makes them more complex and error prone.

    Ry has talked about adding coroutines to Node and presently seems to be opposed. Until then, in the Ruby world with Fibers you can get synchronous I/O on top of an underlying async stack. In Node you can't. The debate transcends mere Ruby vs JavaScript.

    ReplyDelete
  10. This comment has been removed by the author.

    ReplyDelete
  11. This comment has been removed by the author.

    ReplyDelete
  12. Have you checked out Zed Shaw's Mongrel2? It's a HTTP server based on Zed's original HTTP Parser and ZeroMQ, a really promising evented networking library. It is completely language agnostic, so it's like Node.js or EventMachine, only you can use it from any language. There are already bindings out for lots of languages, and bindings are quite easy to write. So it's a modern web server into which you can plug your favorite web app platform in your favorite language. It also has some very innovative features like supporting WebSockets, N handlers responding to M requests, plus a few others. Worth a look.

    ReplyDelete
  13. While you are mostly right, there is a significant flaw with assuming threads in Ruby solve anything: most machines can't run more than 2-3000 threads at any time. The scheduling cost kills it.

    You'd need green threads multiplexed over native threads + thread pool for blocking I/O. But that just tries to fix the fact that I/O is generally sync by default, when it should be async by default with sync optionally implemented on top.

    And Erlang gives you just that :) So yeah, Reia, LFE and Efene are cool.

    ReplyDelete
  14. I have ruby on rails app with me,but it does not support asynchronous mechanism.So I wanna integrate my app with JRuby to get the asynchronous feature.Would it be possible.If so how do I proceed.
    Any help would be greatly appreciated,thank you very much..

    ReplyDelete
  15. The content quality is really great. The full document is entirely amazing. Thank you very much share useful concepts.This way of running explained is very clearly.
    SEO Training in Chennai
    Best SEO Training Institute in Chennai

    ReplyDelete
  16. Had a laugh here: "Why write in JavaScript when you can write in Ruby"

    Would be interested to know how much of this article is relevant in 2017, especially with the addition of async/await to ES6, which makes writing async code very similar to sync code.

    ReplyDelete
  17. شركة شراء اثاث مستعمل بالرياض
    بيع اثاث مستعمل بالرياض
    شراء اثاث مستعمل بالرياض
    شراء اثاث مستعمل الرياض
    اثاث مستعمل بالرياض
    اثاث مستعمل
    شراء اثاث مستعمل
    شركات شراء اثاث مستعمل بالرياض
    شراء الاثاث المستعمل بالرياض تعرض عليكم عملائنا الكرام اذا اردتم بيع ما في منزلكم من مشتملات كالأثاث او المكاتب او المطابخ او غرف النوم او غرف المعيشه فقك بالتواصل مع محلات شراء الاثاث المستعمل بالرياض لاننا لانقوم ببخس اسعار اثاثك بل يتم شرائة بأعلي سعر عن باقي السوق فنحن نضمن لك حقوقك كاملة ونضمن لك بيع اغراض منزلك في المكان الصحيح حيث اننا نوفر عليكم رسوم النجار او الحرفي الذي سيقوم بفك وتنزيل الاثاث فكل هذا يتم من خلال التواصل مع اهل الخبرة والتخصص في شراء الاثاث المستعمل بالرياض

    ReplyDelete
  18. I was really excited about your daily updates. If you have new update me.
    SEO Course Chennai
    SEO Course

    ReplyDelete
  19. keep sharing your information regularly for my future reference. This content creates a new hope and inspiration with in me. Thanks for sharing article like this

    https://www.besanttechnologies.com/training-courses/software-testing-training/selenium-training-institute-in-chennai

    https://www.besanttechnologies.com/robotic-process-automation-rpa-training-in-chennai

    https://www.gangboard.com/software-testing-training/selenium-training


    https://www.gangboard.com/rpa-online-training/openspan-training

    ReplyDelete
  20. keep sharing your information regularly for my future reference. This content creates a new hope and inspiration with in me. Thanks for sharing article like this


    Selenium Training in Chennai

    RPA Training in Chennai

    ReplyDelete
  21. I have read your blog its very attractive and impressive. I like it your blog.
    HTML5 training in chennai
    HTML5 training in chennai

    ReplyDelete
  22. Thank you for sharing such great information with us. I really appreciate everything that you’ve done here and am glad to know that you really care about the world that we live in.
    AWS Training in Chennai
    AWS Training in Bangalore
    AWS Training in Anna Nagar
    AWS Training in T nagar

    ReplyDelete
  23. your post is the very organized way and easily understandable. Doing a good job. Thank you for sharing this content.
    rpa training in chennai | rpa training in velachery | rpa training in chennai omr


    ReplyDelete
  24. Such a nice article on Blueprism .. I love to read your article on Blueprism because your way of representation and writing style makes it intresting. The speciality of this blog on Blueprism is that the reader never gets bored because its same Intresting from 1 line to last line. Really appericable post on Blueprism.
    Thanks and Regards,
    Blueprism training in chennai

    ReplyDelete

  25. Awwsome informative blog ,Very good information thanks for sharing such wonderful blog with us ,after long time came across such knowlegeble blog. keep sharing such informative blog with us.
    Airport Management Courses in Chennai | Airport Management Training in Chennai | Diploma in Airport Management Course in Chennai | Airlines Training Chennai | Airline Academy in Chennai

    ReplyDelete
  26. Outstanding blog thanks for sharing such wonderful blog with us ,after long time came across such knowlegeble blog. keep sharing such informative blog with us. Machine learning training in chennai | machine learning course fees in chennai | machine learning with python course in Chennai

    ReplyDelete
  27. Great efforts put it to find the list of articles which is very useful to know, Definitely will share the same to other forums. Roles and reponsibilities of hadoop developer | hadoop developer skills Set | hadoop training course fees in chennai | Hadoop Training in Chennai Omr

    ReplyDelete
  28. Book cheap Umrah packages with our premium Umrah services. Find more at our website.

    ReplyDelete
  29. While you are for the most part appropriate, there is a huge blemish with accepting strings in Ruby illuminate anything. You'd require green strings multiplexed over local strings + string pool for blocking I/O. In any case, that just attempts to settle the way that I/O is by and large match up as a matter of course, when it ought to be async of course with adjust alternatively actualized to finish everything.

    Thanks&Regards
    Katherine

    ReplyDelete
  30. Nice tutorial. Thanks for sharing the valuable information. it’s really helpful. Who want to learn this blog most helpful. Keep sharing on updated tutorials…
    Java training in Chennai | Java training institute in Chennai | Java course in Chennai

    Java training in Bangalore | Java training institute in Bangalore | Java course in Bangalore

    ReplyDelete
  31. Awesome article. It is so detailed and well formatted that i enjoyed reading it as well as get some new information too.
    Selenium training in Chennai

    ReplyDelete

  32. Thank you for your amazing article! Absolutely it's very great concept and very attractive to readers. I like to additional information from your blog...
    Spoken English Classes in Chennai
    Best Spoken English Classes in Chennai
    Spoken English Class in Chennai
    Spoken English in Chennai
    Best Spoken English Class in Chennai

    ReplyDelete

  33. This information is impressive. I am inspired with your post writing style & how continuously you describe this topic. Eagerly waiting for your new blog keep doing more.
    German Classes in Chennai
    German Language Classes in Chennai
    Big Data Training in Chennai
    Hadoop Training in Chennai
    Selenium Course in Chennai
    selenium testing training in chennai

    ReplyDelete
  34. Multiple Training in dubai, ielts courses,Interior design,interior design courses in dubai,Computer Courses,computer courses in dubai,Management Courses,office management courses,English Courses in dubai. Learn more: http://newvision-tc.com/

    ReplyDelete
  35. You are doing a great job. I would like to appreciate your work for good accuracy
    Regards,
    Selenium Training Institute in Chennai | Selenium Testing Training in chennai

    ReplyDelete
  36. Inspiring writings and I greatly admired what you have to say , I hope you continue to provide new ideas for us all and greetings success always for you..Keep update more information..
    Selenium Training in Chennai | SeleniumTraining Institute in Chennai

    ReplyDelete
  37. https://www.veilleuse.shop/produit/veilleuse-coranique-munawara/
    La veilleuse coranique bluetooth avec sa télécommande pour offrir.
    Cadeau ramadam idéal
    La veilleuse coranique personnalisée pas cher
    Veilleuse coranique personnalisée
    Veilleuse coranique personnalisée

    Découvrez La veilleuse coranique Munawara
    Video de la Veilleuse coranique munawara
    Veilleuse coranique munawara


    Je travailles sur un projet de fabrication de cornes de gazelle personnalisée
    cornes de gazelle expressives
    cornes de gazelle délicieuses
    Merci de laisser ce lien c'est sympa...

    Le casque vapeur hair steamer permet de lutter contre la sécheresse, la chute des cheveux et leur mauvaise santé , dans le confort de votre domicile. Le hair steamer est un casque vapeur qui apporte une dose d'hydratation pour les cheveux crépus.
    Hair steamer vapohair
    Lee hair steamer casque vapeur est recommendé par fes femmes aux cheveux crépus
    Casque vapeur
    La casque vapeur hair steamer apporte beaucoup de bienfait au cheveux crépus de type afro Hair.
    hair steamer Casque vapeur hydratation cheveux crépus
    hair steamer
    Le hair steamer casque vapeur fournit une cure intense contre les chutes et pour favoriser la repousse.
    Le hair steamer est un casque à vapeur sûr, une utilisation et un entretien facile

    ReplyDelete
  38. Thank you so much for given such an informative blog. Get the best Website Designing and Development Services by Ogeninfo.
    Website Designing Company in Delhi

    ReplyDelete
  39. Feeling so good to read your information's in the blog.Thanks for sharing your ideas with us and add more info.

    Robotics Automation Process Online Training


    Ruby On Rails Online Training


    Sailpoint Online Training

    ReplyDelete
  40. Get the best performing Mutual Fund by Mutual Fund Wala and know the best investment schemes.
    Mutual Fund Agent

    ReplyDelete
  41. Hello I am so delighted I found your blog, I really found you by mistake, while I was looking on Yahoo for something else, anyways I am here now and would just like to say thanks for a tremendous post. Please do keep up the great work.
    Data Science training institute in bangalore

    ReplyDelete

  42. Thanks for sharing the knowledgeable stuff to enlighten us no words for this amazing blog.. learnt so many things I recommend everyone to learn something from this blogger and blog.. I am sharing it with others also
    IT Software Training in Chennai | Python Training in Chennai | Dot Net Training in Chennai

    ReplyDelete
  43. Looking for best TNPSC study materials to prepare for the examination? Make use of our samacheer kalvi books and other study guide to learn from experts. TNPSC One Time Registration

    ReplyDelete
  44. The article is so informative. This is more helpful for our
    software testing training online
    best selenium online training in chennai. Thanks for sharing

    ReplyDelete
  45. Nice blog, Visit Kalakutir Pvt Ltd for Godown Line Marking Painting, Base Company Logo Painting, and School Bus Painting.
    Base Company Logo Painting

    ReplyDelete
  46. پاک کردن نام همسر از شناسنامه بعد از طلاق توافقی قطعا جزوه حریم خصوصی است. حفظ حریم خصوصی قطعا یکی از خط قرمز های هر شخص در زندگی محسوب می شود. اینکه شخص برای بار چندم است که ازدواج میکند قطعا یک موضوع شخصی است.
    بسیاری از زوجین که برای بار دوم ازدواج می کنند این موضوع برای آنها اهمیت دو چندان پیدا می کند. چرا که اگر اطرافیان و آشنایان از این موضوع بویی ببرند قطعا یک کلاغ چهل کلاغ خواهد شد. به همین دلیل افراد دوست ندارند بعد از طلاق اسم همسرشان در شناسنامه بماند و اقدام به پاک کردن نام همسر از شناسنامه می کنند.
    سازمان ثبت احوال کشور یا دیدن چنین موضوعاتی، اقدام به وضع قوانین در این مورد کرد. لذا زین پس افراد می توانند نام همسر خود را حتی بعد از دوبار ازدواج حذف کنند. اما قطعا دارای شرایط و قوانینی است تا از سواستفاده افراد جلوگیری شود. در صورت بروز هرگونه سوال و ابهام با گروه وکلای مستر دادیار در ارتباط باشید.
    قانون پاک کردن نام همسر از شناسنامه
    پاک کردن نام همسر از شناسنامه سال هاست که برای افراد مطلقه امکانپذیر است. هر شخصی چه زن و چه مرد می تواند پس از ثبت ازدواج بعدی خود (ازدواج بعد از طلاق)، اقدام به حذف نام همسر از شناسنامه کنند. برخی نسبت به اینکه چرا باید بعد از ازدواج این اتفاق بیافتد ناراضی هستند. دلیل این امر این است که زن و شوهر باید از موضوعات مهم این چنینی نسبت به یکدیگر اطلاع داشته باشند. به همین خاطر پاک کردن نام همسر از شناسنامه بعد از ازدواج ممکن است.
    البته در صورتی که طلاق در دوران عقد باشد، نیاز به ازدواج نیست و می توانید بعد از طلاق نام همسر را حذف کنید. طلاق در دوران عقد به این معنی است که زوجه هنوز باکره باشد و مقاربتی بین زوجین شکل نگرفته باشد. این نوع طلاق از نوع طلاق بائن است و مرد حق رجوع نیز ندارد. این موضوع در هنگام طلاق با ارائه سند پزشکی به دادگاه ارائه می گردد.
    در صورتی که زوجه در ازدواج دوم باشد. یعنی باکره نیست و از همسر دومی که هنوز با او مقاربتی نداشته قصد طلاق دارد. در این صورت اقرار طرفین در دادگاه سند محسوب می گردد. این موضوع بنا به شهری که در آن هستید ممکن است کمی متفاوت باشد.

    ReplyDelete
  47. Nice Presentation and its hopefull words..
    if you want a cheap web hostinng in web
    cheap web hosting company chennai

    ReplyDelete
  48. thanks for your details.i got more information. It's very nice and amazing.web design company in velachery Qbigpro branding solution is the best web design company in velachery web design company in velachery.we will create the web site and managing the site.we will help for all business.website is very important for all business.

    ReplyDelete
  49. La sciatique est une douleur vive ressentie le long d’un des 2 nerfs sciatiques. Situés à l’arrière de chacune des jambes, ce sont les nerfs les plus volumineux de l’organisme (voir schéma). Ils rejoignent la colonne vertébrale au bas du dos, à la hauteur des vertèbres lombaires et sacrées (tout juste au-dessus du coccyx) sciatique

    ReplyDelete
  50. Great post. It was so emotional. Yes, life cannot be predicted to live your life every second.
    So find out your dreams and achieve it. just spent 2 min here in the comment:
    Are you looking for the safest gates in the world?
    Gates for homes are now made of aluminium with adjustable hinges. These gate designs that are
    manufactured by Elite gates are the world’s first automatic trackless folding gates in India. The folding
    model gates that are available for homes have various advantages attached to it and thus the people of
    India craves for these gates to ensure the safety of their households and also enhance the beauty of their
    homes.

    ReplyDelete
  51. For the best training in python in bangalore, Visit:
    Python training in Bangalore

    ReplyDelete
  52. Thanks for this amazing blog, I really appreciate with your blog. Ogen Infosystem provides one of the best Website Designing Services in Delhi.
    Website Designing Company

    ReplyDelete
  53. This comment has been removed by the author.

    ReplyDelete
  54. Visit here for know more about Big data/Hadoop -> Big Data and Hadoop Training in Bangalore

    ReplyDelete
  55. This comment has been removed by the author.

    ReplyDelete
  56. Thanks for sharing, nice post! Post really provice useful information!
    ORACLE TRAINING IN CHENNAI

    ReplyDelete
  57. Nice Blog
    For DATA SCIENCE training in Bangalore, Visit:
    Data Science training in Bangalore

    ReplyDelete
  58. Nice Post
    Visit for the best AI training in Bangalore:-
    AI training in Bangalore

    ReplyDelete
  59. Thanks for sharing this blog. really nice and useful for me
    big data training in chennai

    ReplyDelete
  60. Thank you for sharing such a nice and interesting blog with us. I have seen that all will say the same thing repeatedly. But in your blog, I had a chance to get some useful and unique information.

    Digital Marketing Training In Hyderabad
    sem training in hyderabad
    seo training in hyderabad
    SMM Training In Hyderabad

    ReplyDelete
  61. This is a nice and informative, containing all information and also has a great impact on the new technology. Thanks for sharing it
    website designing Service

    ReplyDelete
  62. This is really great news. Thank you for sharing it with us!

    septic pumping san diego

    ReplyDelete
  63. This comment has been removed by the author.

    ReplyDelete
  64. I have perused your blog its appealing, I like it your blog and keep update.
    php development company,
    php development india,
    php application development,
    php website development,
    php web development,
    php framework,
    Thanks for sharing useful information article to us keep sharing this info

    ReplyDelete
  65. ترجمه کتاب باید بدست مترجم حرفه ای ترجمه شود که تخصصی در این رشته داشته باشد که در سایت ترجمه انلاین میتواند ترجمه خود را انجام دهید

    ReplyDelete
  66. ترجمه کتاب باید بدست مترجم حرفه ای ترجمه شود که تخصصی در این رشته داشته باشد که در سایت ترجمه انلاین میتواند ترجمه خود را انجام دهید

    ReplyDelete
  67. i have read it thanks for giving such a wonderful Blog for reader.
    123 movies

    ReplyDelete
  68. Great blog thanks for sharing The tone of every picture on your website, Instagram post and Facebook Ads counts more than you think. Having a simple digital marketing is not enough for your brand. You need a graphic designing company that creates a unique brand identity that matters. An idea that goes beyond just a product - a thought leader in the industry.
    digital marketing agency in chennai

    ReplyDelete
  69. Nice blog thanks for sharing Set up a aesthetic work environment that employees love to spend time in and relieve their stress. Your company needs the best corporate gardening service in Chennai and Karuna Nursery Gardens in happy to oblige you in the endeavour to make your infrastructure something worth flaunting about.
    plant nursery in chennai

    ReplyDelete
  70. Excellent blog thanks for sharing Buy the best beauty parlour products wholesale in Chennai at Pixies Beauty Shop. Thousands of global top-tier brands to choose from and friendly faces all over, we would love to make your Salon journey, one the world recognizes.
    Cosmetics Shop in Chennai

    ReplyDelete
  71. ترجمه تخصصی روانشناسی
    ، ترجمه تخصصی پزشکی، ترجمه تخصصی انگلیسی به فارسی، ترجمه تخصصی فارسی به انگلیسی و سایر خدمات در وب سایت ترجمه آنلاین

    ReplyDelete
  72. This post is really nice and informative. The explanation given is really comprehensive and informative . Thanks for sharing such a great information..Its really nice and informative . Hope more artcles from you. I want to share about the best java video tutorials with free bundle videos provided and java training .

    ReplyDelete
  73. מעולה. תודה על הכתיבה היצירתית.
    חברת קבוצת גבאי

    ReplyDelete
  74. תודה על השיתוף. מחכה לכתבות חדשות.
    שולחן פינת אוכל

    ReplyDelete
  75. כל מילה. תודה על השיתוף, מחכה לעוד פוסטים בנושא
    שולחן אוכל

    ReplyDelete
  76. סופסוף מישהו שתואם לדעותיי בנושא. תודה.
    עיצוב עצמות לחיים

    ReplyDelete
  77. פוסט נחמד. חייב לשתף עם העוקבים שלי.
    ארגון חתונה

    ReplyDelete
  78. I have read your blog its very attractive and impressive. I like it your blog.

    ReplyDelete
  79. כתיבה מעולה, אהבתי. אשתף עם העוקבים שלי.
    בייביזמול

    ReplyDelete
  80. כל מילה. תודה על השיתוף, מחכה לעוד פוסטים בנושא.
    נכס מניב

    ReplyDelete
  81. This comment has been removed by the author.

    ReplyDelete

  82. אין ספק שזה אחד הנושאים המעניינים. תודה על השיתוף.
    מערכות אזעקה

    ReplyDelete
  83. רציתי רק לשאול, אפשר לשתף את הפוסט בבלוג שלי?
    ניהול מוניטין ברשת

    ReplyDelete
  84. אין ספק שזה אחד הנושאים המעניינים. תודה על השיתוף.
    הדפסת תמונה על בלוק עץ

    ReplyDelete
  85. Nice. Blogs. Thanks for the sharing with us. Koneez Academy offers the best travel and tourism course in Delhi. The admission to 1-year diploma in tourism and travel course is open. For more details Visit on Website.


    http://koneezacademy.in/airport-ground-staff-training/
    http://koneezacademy.in/advance-diploma-in-tourism-airlines-2/
    http://koneezacademy.in/advance-diploma-in-tourism-airlines-2/
    http://koneezacademy.in/iata-consultant-programme-montreal-canada/

    ReplyDelete
  86. I like the article that you published to get Becklink 1, thank you.
    obat penggugur kandungan di apotik

    ReplyDelete
  87. It's not necessary to have a traditional degree marketing degree to get started, although some training will help to get your foot in the door. The things you can do right now to start a digital marketing career are.
    ExcelR Digital Marketing Courses In Bangalore

    ReplyDelete
  88. I am inspired with your post writing style & how continuously you describe this topic. After reading your post, software testing tutorial thanks for taking the time to discuss this, I feel happy about it and I love learning more about this topic.

    ReplyDelete


  89. This post is really nice and informative. The explanation given is really comprehensive and informative. I also want to say about the digital marketing course near me

    ReplyDelete
  90. PYTHON TRAINING IN JAIPUR
    Hey, Are you looking for the best python training in Jaipur ,so grab this opportunity . DZONE is here for you with the best online and offline Classes ,Techniques and Experiences .Join us to improve your skills and Better Future
    REGISTRATION OPEN!!
    ENROLL NOW!!
    To book free demo session, feel free to call us at 8432830240 or 0141-4108506.

    ReplyDelete
  91. One of the greatest benefits of digital marketing is that it allows you to target your ideal buyers.
    We Provide complete digital marketing course in 3 months.
    include in this course: SEO, SEM,GOOGLE ADS,Email Marketing, Web Development etc.
    ✔️100% Best knowledge
    ✔️professional and experienced
    ✔️practical training
    ✔️100% certification after the complete cours
    ✔️Online Classes are available

    ReplyDelete
  92. DZone Internship/Training 2020
    Are you searching for Python | Machine Learning | Data Science | Tableau | Java | Android | P.H.P | Digital Marketing Internship in Jaipur? Join our project based Job-Oriented online/offline Training under expert guidance. Hurry!! 50% discount available on all Courses. To Avail this Opportunity Reserve Your Seats Now !! ENROLL NOW!! To book free demo session, feel free to call us at 8432830240 or 0141-4108506..

    ReplyDelete
  93. אין ספק שהפוסט הזה דורש שיתוף. תודה.
    מארזים ליולדת

    ReplyDelete
  94. הייתי חייבת לפרגן, תודה על השיתוף.
    ברוקר לי

    ReplyDelete
  95. Amazing post, Thank you for presenting a wide variety of information that is very interesting to see in this artikle. | Home lifts malaysia

    ReplyDelete
  96. I was really impressed by seeing this blog, it was very interesting and it is very useful for me. Home lifts Dubai

    ReplyDelete
  97. Thanks you for sharing this unique useful information content with us. Really awesome work. keep on blogging.
    Python Training
    Digital Marketing Training
    AWS Training

    ReplyDelete
  98. This is one of the good content I have ever seen about recruitment process. My name is Mazhar, I'm working as Digital Marketing Director at leading Digital Marketing Agency Riyadh. So, this content will help us in future. Because, we already grew one of the best Social Media Agency in Riyadh, so we need more and more staffs after the Covid-19 crisis to our Marketing agency in Riyadh. Thanks for this content.

    ReplyDelete
  99. לגמרי פוסט שדורש שיתוף תודה.
    קנבס עם תמונות

    ReplyDelete