Twisted (1) -- What is asynchronous, twisted -- What is asynchronous

Source: Internet
Author: User
Tags rabbitmq

Twisted (1) -- What is asynchronous, twisted -- What is asynchronous

I have long wanted to write an article about python's two asynchronous libraries, twisted and tornado. When developing python tcpserver, we usually only use three libraries, twisted, tornado, and gevent. The efficiency of asynchronous libraries represented by twisted and tornado is relatively high, however, developers have high requirements. We are all discussing the high efficiency of Asynchronization. What is Asynchronization? Why is it more efficient? The world is always conservation. What does asynchronous efficiency sacrifice at the same time? Let's talk about the python asynchronous library today.

In fact, the asynchronous library we are talking about is based on the computer model Event Loop, which is not only available in python. If you use ajax, you will know that ajax generally obtains data asynchronously. In fact, the whole js is a single thread Based on eventloop. Well, it's far away. So what is Eevent Loop? See

We know that every program running starts a process. In the history of the tcpserver server, there are three main methods to process client connections.

For convenience, we think of the tcpserver as a process for banks to handle their business. Every time you go to a bank to handle the business, the actual process is not long. In many cases, bank staff are also waiting. For example, if she operates a business and the computer has not responded in time, she has nothing to do and can only wait. When printing all kinds of files, she is also waiting. This is actually the same as our tcpserver. Many applications, our tcpserver has been waiting.

First, the queue is blocked. The bank opens only one window. When everyone comes, they have to wait in the queue. In most cases, bank staff are waiting for computer and printer operations. This method has the lowest efficiency.

Second, sub-process. Each time a customer arrives, a bank opens a window for special reception, but the Bank window is not infinite. Every time a window is opened, there is a price. This method is better than above, but the efficiency is not that high.

Third, thread. The bank saw that every clerk had been busy, but the waiting time was too long to improve efficiency. As a result, the leader stipulated that each clerk should process 10 customers at the same time (one process starts 10 threads), and then process customer 2 or other customers in the spare time for processing customer 1. Well, it seems that the efficiency has improved, but the salesman is extremely prone to errors when receiving so many customers at the same time (the thread mode is indeed prone to errors, and it is not easy to control, generally, threads only process a single and simple task ).

 

Well, after studying historical issues, the bank finally thought of the ultimate Big method, asynchronous. The Bank invited robots to serve as salesmen and put all the customers in a circle (this circle is eventloop). The robots stood in the middle of the circle and kept rotating (infinite loop ). Each time a robot receives a customer, it adds the customer to this circle. Then start processing the business and processing the business. If you encounter any busy waiting behavior when processing the business, such as waiting for printer operation or computer operation, all of them will first hook up the business and save it (Save the Context Environment, you can actually think of it as a pressure stack), and then continue to rotate. If there are other businesses, process it and continue the above actions. At this time, a business waits for completion and sends a signal to the robot. The robot pulls out the suspended business environment (pulls the saved Context Environment out of the stack) and continues to process it, until the processing is complete.

The whole process is an infinite loop. When an event is encountered, it will be processed. If the event needs to wait, it will be suspended and the loop will continue. If the wait is complete, it will send a signal to the loop and continue processing, continue the loop. This is asynchronous.

Compared with the three historical processes, is asynchronous much more efficient than before? But there is also a price, especially for programmers. When should I save the context? When will it come out? What should I do when an error occurs? And so on. We will gradually introduce this issue later.

  

  

Next we will go back to the actual twisted, which is an official reference image. I think it is a good explanation of the twisted operation process. Through this figure, combined with my example above, I want you to have a basic understanding of the twisted running process.

In fact, this reactor loop integrates the core things of twisted, and all events are in this "circle". On this basis, adding socket is the process of accepting network client data. This circle can also work without a socket. In the future, we will encounter the situation of combining twisted with rabbitmq. The consumers of rabbitmq are also a "circle", which is actually a "circle" of twisted, however, any twisted event requires Asynchronization.

With so many concepts mentioned above, we can use the code to try twisted. I found that many blogs on the Internet started to introduce twisted, which often has a lot of code, and beginners don't know how to get started. This is a problem for beginners. We will try to solve this problem today.

from twisted.internet import reactorreactor.run()

If the code is as above, a line of code is run directly, and then the "circle" will run. The client cannot write data without a socket.

On this basis, add a bit of material.

  

import timedef hello():    print("Hello world!===>" + str(int(time.time())))from twisted.internet import reactorreactor.callWhenRunning(hello)reactor.callLater(3, hello)reactor.run()

Look at the code, I think, you just don't understand twisted, look at the literal meaning, also know what's going on. CallWhenRunning: triggers the hello function when the reactor starts running. callLater is triggered three seconds later. Check the result

/usr/bin/python3.5 /home/yudahai/PycharmProjects/test0001/test001.pyHello world!===>1466129667Hello world!===>1466129670

The result is the same, isn't it easy? Yes, simple reactor is indeed very simple. Let's take a look at the complex tasks.

import timedef hello(name):    print("Hello world!===>" + name + '===>' + str(int(time.time())))from twisted.internet import reactor, tasktask1 = task.LoopingCall(hello, 'ding')task1.start(10)reactor.callWhenRunning(hello, 'yudahai')reactor.callLater(3, hello, 'yuyue')reactor.run()

In the function, a parameter is added, and a cyclic task taks1 is added. Task 1 runs every 10 seconds. Task is often used with twisted, because we will poll to detect unexpected disconnection of the client on each connection. In this case, task is used. Okay. Let's take a look at the results.

/usr/bin/python3.5 /home/yudahai/PycharmProjects/test0001/test001.pyHello world!===>ding===>1466130033Hello world!===>yudahai===>1466130033Hello world!===>yuyue===>1466130036Hello world!===>ding===>1466130043Hello world!===>ding===>1466130053Hello world!===>ding===>1466130063Hello world!===>ding===>1466130073Hello world!===>ding===>1466130083Hello world!===>ding===>1466130093Hello world!===>ding===>1466130103

As you can see, We should basically use the daily twisted "circle.

Well, it's easy to use, but it seems like this is quite simple. I haven't mentioned it on the Internet. How is it difficult for twisted? It seems that there is no price in the middle? Why must I be asynchronous? Why cannot it be blocked in the middle? Well, the above example does not show. Let's look at the following code to see the blocking effect. As we all know, we cannot access the google website here. Let's try visiting the google website in the middle to see what the results will look like.

import timeimport requestsdef hello(name):    print("Hello world!===>" + name + '===>' + str(int(time.time())))def request_google():    res = requests.get('http://www.google.com')    return resfrom twisted.internet import reactor, taskreactor.callWhenRunning(hello, 'yudahai')reactor.callLater(1, request_google)reactor.callLater(3, hello, 'yuyue')reactor.run()

At the beginning, I ran a printing task, which was non-blocking. Then, one second later, I sent a request pointing to google, and then I ran the print at 3rd seconds. View results

/usr/bin/python3.5 /home/yudahai/PycharmProjects/test0001/test001.pyHello world!===>yudahai===>1466130855Hello world!===>yuyue===>1466130984Unhandled ErrorTraceback (most recent call last):  File "/home/yudahai/PycharmProjects/test0001/test001.py", line 21, in <module>    reactor.run()  File "/usr/local/lib/python3.5/dist-packages/twisted/internet/base.py", line 1194, in run    self.mainLoop()  File "/usr/local/lib/python3.5/dist-packages/twisted/internet/base.py", line 1203, in mainLoop    self.runUntilCurrent()--- <exception caught here> ---  File "/usr/local/lib/python3.5/dist-packages/twisted/internet/base.py", line 825, in runUntilCurrent    call.func(*call.args, **call.kw)  File "/home/yudahai/PycharmProjects/test0001/test001.py", line 10, in request_google    res = requests.get('http://www.google.com')  File "/usr/local/lib/python3.5/dist-packages/requests/api.py", line 67, in get    return request('get', url, params=params, **kwargs)  File "/usr/local/lib/python3.5/dist-packages/requests/api.py", line 53, in request    return session.request(method=method, url=url, **kwargs)  File "/usr/local/lib/python3.5/dist-packages/requests/sessions.py", line 468, in request    resp = self.send(prep, **send_kwargs)  File "/usr/local/lib/python3.5/dist-packages/requests/sessions.py", line 576, in send    r = adapter.send(request, **kwargs)  File "/usr/local/lib/python3.5/dist-packages/requests/adapters.py", line 437, in send    raise ConnectionError(e, request=request)requests.exceptions.ConnectionError: HTTPConnectionPool(host='www.google.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7fc189c69e48>: Failed to establish a new connection: [Errno 101] Network is unreachable',))

Let's take a look at the interval between two prints, which is about 130 seconds apart. That is to say, in the middle of 130 seconds, this program has nothing to do, just waiting. Of course, my example is a bit extreme, but in the actual process, access to the database, access to the network, may be blocked. Once the program is blocked, the efficiency will be extremely low.

How can this problem be solved? There are two methods. One is to use the httpclient provided by twisted for access. The httpclient provided by twisted is asynchronous and does not block the operation of the entire reactor; the second is running in the thread mode. Note that the thread here is not a common python thread, but a self-contained thread of twisted. When it is accessed, it will send a signal to the reactor. Next, let's try in the middle 2 method.

# coding:utf-8import timefrom twisted.web.client import Agentfrom twisted.web.http_headers import Headersfrom twisted.internet import reactor, task, deferdef hello(name):    print("Hello world!===>" + name + '===>' + str(int(time.time())))@defer.inlineCallbacksdef request_google():    agent = Agent(reactor)    try:        result = yield agent.request('GET', 'http://www.google.com', Headers({'User-Agent': ['Twisted Web Client Example']}), None)    except Exception as e:        print e        return     print(result)reactor.callWhenRunning(hello, 'yudahai')reactor.callLater(1, request_google)reactor.callLater(3, hello, 'yuyue')reactor.run()

This is the code of the non-blocking version. In the code, the request returns a delayed object, so it does not block the reactor and looks at the result.

/usr/bin/python2.7 /home/yudahai/PycharmProjects/test0001/test001.pyHello world!===>yudahai===>1466386544Hello world!===>yuyue===>1466386547User timeout caused connection failure.

In addition to accessing google, all others come back on time, and access to google does not block reactor.

The above is accessed in a non-blocking way. In fact, in the actual process, many of our libraries do not have APIs in the non-blocking mode. To use the non-blocking mode, we must return the twisted defer object, if you write a library and write an asynchronous version for twisted, this is definitely difficult. In addition, even if your functions are not very complex, you can use the thread mode. twisted itself accesses the database in the thread mode. Let's take a look at the code of the thread mode.

# coding:utf-8import timeimport requestsfrom twisted.internet import reactor, task, deferdef hello(name):    print("Hello world!===>" + name + '===>' + str(int(time.time())))def request_google():    try:        result = requests.get('http://www.google.com', timeout=10)    except Exception as e:        print e        return     print(result)reactor.callWhenRunning(hello, 'yudahai')reactor.callInThread(request_google)reactor.callLater(3, hello, 'yuyue')reactor.run()

The code is simple, that is, replacing request_google with the thread mode. Check the result.

/usr/bin/python2.7 /home/yudahai/PycharmProjects/test0001/test001.pyHello world!===>yudahai===>1466387418Hello world!===>yuyue===>1466387421HTTPConnectionPool(host='www.google.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7fc9da0b1ad0>: Failed to establish a new connection: [Errno 101] Network is unreachable',))

Does it achieve the same purpose? Well, at this time, we may be wondering, since the thread can also thread the blocked code, why do we still directly write asynchronous code? Asynchronous code is hard to write, ugly, and error-prone.

There are actually several reasons for this. In twisted, threads cannot be used in large quantities.

1. Efficiency. If we use a thread, why do we still use twisted? The thread switches cpu scheduling frequently. If a large number of threads are used, the cpu resources are greatly wasted and the efficiency is greatly reduced.

2. thread security. If the first problem has some reason, the thread security issue cannot be ignored. For example, when twisted is used to accept network data, it is not thread-safe. If data is accepted in thread mode, the program will crash. Twisted only supports a very small number of APIs. In fact, the most widely used example is the message queue receiving system. Many junior programmers use the thread mode to accept the message queue. It is okay at the beginning. After the result runs for a while, you will find that the program cannot normally accept data, and no error is reported. Twisted officially recommends that you use Asynchronous libraries as long as you have asynchronous libraries. threads only perform simple and not frequent operations.

  

Now, let's talk about this in this chapter. In the next chapter, we will continue to talk about twisted as a tcpserver, introduce the previous flask api series project, and create a chat system.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.