Redis完毕简单信息队列

JSF提供了汪洋的UI标签来简化创制视图。那个UI标签类似于ASP语言,.NET中的服务器组件。使用那些标签,可以通过其value,binding,action,actionListener等质量直接绑定到托管Bean的属性,实例或者措施上。

职分异步化

开拓浏览器,输入地方,按下回车,打开了页面。于是一个HTTP请求(request)就由客户端发送到服务器,服务器处理请求,重返响应(response)内容。

俺们每天都在浏览网页,发送大大小小的请求给服务器。有时候,服务器收到了请求,会意识她也急需给此外的服务器发送请求,或者服务器也亟需做其它一些事情,于是最初们发送的请求就被卡住了,也就是要等待服务器完毕其余的政工。

更加多的时候,服务器做的额外事情,并不须求客户端等待,那时候就足以把这么些额外的政工异步去做。从事异步职务的工具有无数。主要原理依然处理通报音讯,针对布告新闻日常选取是队列结构。生产和消费音信举办通讯和业务完结。

1、JSF中的三大主导器件:

生儿育女消费与队列

上述异步职务的兑现,可以抽象为劳动者消费模型。如同一个餐馆,厨子在煮饭,吃货在进食。倘使大厨做了重重,暂时卖不完,大厨就会休息;如若客户很多,大厨快马加鞭的无暇,客户则要求逐步等待。达成生产者和顾客的办法用很多,上面接纳Python标准库Queue写个小例子:

import random
import time
from Queue import Queue
from threading import Thread

queue = Queue(10)

class Producer(Thread):
    def run(self):
        while True:
            elem = random.randrange(9)
            queue.put(elem)
            print "厨师 {} 做了 {} 饭 --- 还剩 {} 饭没卖完".format(self.name, elem, queue.qsize())
            time.sleep(random.random())

class Consumer(Thread):
    def run(self):
        while True:
            elem = queue.get()
            print "吃货{} 吃了 {} 饭 --- 还有 {} 饭可以吃".format(self.name, elem, queue.qsize())
            time.sleep(random.random())

def main():
    for i in range(3):
        p = Producer()
        p.start()
    for i in range(2):
        c = Consumer()
        c.start()

if __name__ == '__main__':
    main()

大致输出如下:

厨师 Thread-1 做了 1 饭 --- 还剩 1 饭没卖完
厨师 Thread-2 做了 8 饭 --- 还剩 2 饭没卖完
厨师 Thread-3 做了 3 饭 --- 还剩 3 饭没卖完
吃货Thread-4 吃了 1 饭 --- 还有 2 饭可以吃
吃货Thread-5 吃了 8 饭 --- 还有 1 饭可以吃
吃货Thread-4 吃了 3 饭 --- 还有 0 饭可以吃
厨师 Thread-1 做了 0 饭 --- 还剩 1 饭没卖完
厨师 Thread-2 做了 0 饭 --- 还剩 2 饭没卖完
厨师 Thread-1 做了 1 饭 --- 还剩 3 饭没卖完
厨师 Thread-1 做了 1 饭 --- 还剩 4 饭没卖完
吃货Thread-4 吃了 0 饭 --- 还有 3 饭可以吃
厨师 Thread-3 做了 3 饭 --- 还剩 4 饭没卖完
吃货Thread-5 吃了 0 饭 --- 还有 3 饭可以吃
吃货Thread-5 吃了 1 饭 --- 还有 2 饭可以吃
厨师 Thread-2 做了 8 饭 --- 还剩 3 饭没卖完
厨师 Thread-2 做了 8 饭 --- 还剩 4 饭没卖完

a、 JSF容器管理的托管Bean
b、 JSF提供的UI标签,应用界面的UI标签直接绑定到托管Bean
c、 页面导航规则

Redis 队列

Python内置了一个好用的体系结构。大家也足以是用redis完成类似的操作。并做一个简练的异步任务。

Redis提供了三种办法来作消息队列。一个是采纳生产者消费模式情势,别的一个格局就是发布订阅者模式。前者会让一个如故七个客户端监听音信队列,一旦新闻到达,消费者及时消费,哪个人先抢到算哪个人的,借使队列里不曾音讯,则消费者继续监听。后者也是一个或四个客户端订阅信息频道,只要公布者发表新闻,所有订阅者都能接收音信,订阅者都是如出一辙的。

下边大家就来介绍UI标签:

生儿育女消费方式(不提议选用)

紧要使用了redis提供的blpop获取队列数据,若是队列没有多少则阻塞等待,也就是监听。

import redis

class Task(object):
    def __init__(self):
        self.rcon = redis.StrictRedis(host='localhost', db=5)
        self.queue = 'task:prodcons:queue'

    def listen_task(self):
        while True:
            task = self.rcon.blpop(self.queue, 0)[1]
            print "Task get", task

if __name__ == '__main__':
    print 'listen task queue'
    Task().listen_task()

运用redis的brpop情势做队列,经过一段时间,会发现先后不可捉摸的卡主。也就是进度一切ok,redis的lpush也健康,唯独brpop不再消费。该难题尤其糟糕复现,可是接连过了一段时间就会再次出现。本人使用了高并发,高延迟,弱互联网环境等艺术总括复现都并未旗开马到,近期照旧在追寻解决方案。目测依赖redis做brokers的连串的celery也碰到相同的问题
,并且其他语言也有近似问题,但是作者的化解方不适用。估摸难点的来头是redis在处理brpop的时候总是长日子不适用会自动假死。后来利用比较low的方案,每当凌晨3点左右重启一下种类服务。近年来设置了更短的idle连接时间(config
set timeout 10),再观看一下是或不是能复现。
不提出在变更环境使用该方案。若是选择类似方案也赶上了难点,并且有了化解方案,希望你能联络我哈哈哈。
晋级了 redis 3.2 版本之后,运行了一个多月,近日未曾再次出出现堵塞的题材。

2、JSF中的UI标签:

通知订阅情势

应用redis的pubsub作用,订阅者订阅频道,公布者公布信息到频道了,频道就是一个音信队列。

import redis


class Task(object):

    def __init__(self):
        self.rcon = redis.StrictRedis(host='localhost', db=5)
        self.ps = self.rcon.pubsub()
        self.ps.subscribe('task:pubsub:channel')

    def listen_task(self):
        for i in self.ps.listen():
            if i['type'] == 'message':
                print "Task get", i['data']

if __name__ == '__main__':
    print 'listen task channel'
    Task().listen_task()

JSF与JSP的标签的分别在于,JSF的价签可以选用value,binding,action和actionListener等质量直接绑定到托管Bean上边去。

Flask 入口

咱俩独家达成了二种异步职务的后端服务,间接开行他们,就能监听redis队列或频道的信息了。不难的测试如下:

import redis
import random
import logging
from flask import Flask, redirect

app = Flask(__name__)

rcon = redis.StrictRedis(host='localhost', db=5)
prodcons_queue = 'task:prodcons:queue'
pubsub_channel = 'task:pubsub:channel'

@app.route('/')
def index():

    html = """
<br>
<center><h3>Redis Message Queue</h3>
<br>
<a href="/prodcons">生产消费者模式</a>
<br>
<br>
<a href="/pubsub">发布订阅者模式</a>
</center>
"""
    return html


@app.route('/prodcons')
def prodcons():
    elem = random.randrange(10)
    rcon.lpush(prodcons_queue, elem)
    logging.info("lpush {} -- {}".format(prodcons_queue, elem))
    return redirect('/')

@app.route('/pubsub')
def pubsub():
    ps = rcon.pubsub()
    ps.subscribe(pubsub_channel)
    elem = random.randrange(10)
    rcon.publish(pubsub_channel, elem)
    return redirect('/')

if __name__ == '__main__':
    app.run(debug=True)

开行脚本,使用

siege -c10 -r 5 http://127.0.0.1:5000/prodcons
siege -c10 -r 5 http://127.0.0.1:5000/pubsub

可以独家在监听的剧本输入中来看异步新闻。在异步的任务中,可以推行一些耗时间的操作,当然近期这个做法并不知道异步的施行结果,借使急需驾驭异步的实施结果,能够设想规划协程职分依然接纳一些工具如RQ或者celery等。

JSF包蕴两组标签库:jsf_core.tld主旨标签库和html_basic。tld
HTML标签库。

2.1、JSF宗旨标签库:

f:actionListener
f:attribute
f:convertDateTime
f:convertNumber
f:converter
f:facet
f:loadBundle
f:param
f:phaseListener
f:selectItem
f:selectItems
f:setPropertyActionListener
f:subview
f:validateDoubleRange
f:validateLength
f:validateLongRange
f:validator
f:valueChangeListener
f:verbatim
f:view

关于个标签的详尽介绍,可以参照JSF自带的支持文档:

JSF解压目录\tlddocs\index.html

2.2、JSF的HTML标签:

h:commandButton
h:commandLink
h:dataTable
h:form
h:graphicImage
h:inputHidden
h:inputSecret
h:inputText
h:inputTextarea
h:message
h:messages
h:outputFormat
h:outputLabel
h:outputLink
h:outputText
h:panelGrid
h:panelGroup
h:selectBooleanCheckbox
h:selectManyCheckbox
h:selectManyListbox
h:selectManyMenu
h:selectOneListbox
h:selectOneMenu
h:selectOneRadio
h:column

关于个标签的详细介绍,可以参照JSF自带的接济文档:

JSF解压目录\tlddocs\index.html

2.3、UI标签的通用属性:

JSF的UI大都会转变一个或多少个HTML标签,所以拔取那个UI标签有时一些品质是通用的:

id
immediate:是否立即处理UIInput组件和实现了ActionSource接口的UI组件上事件
rendered:指定条件表达式,当条件表达式为true时才会绘制组件
required:指定用户是否必须为组件输入值
requeredMessage:与requered一起使用,如果没有输入时提示信息
value:该组件的值绑定到托管对象上
onblur
onchange
onclick
ondblclick
onfocus
onkeydown
onkeypress
onkeyup
onmousedown
onmousemove
onmouseout
onmouseover
onmouseup
style
styleClass
binding:将组件本身绑定到托管Bean

2.4、<f:view>标签的常用属性:

locale:点名国家语言
renderKitId:JSF根据该属性值拔取相应的绘制器工具箱来绘制该页面
beforePhase:绑定生命周期监听器(必须有public void
beforePhase(Java.faces.event.Phase伊芙nt)形式的签约),JSF会在每个生命周期阶段(除了回复视图)之前调用该方法。
afterPhase:绑定生命周期监听器(必须有public void
afterPhase(java.faces.event.Phase伊夫nt)格局的签约),JSF会在每个生命周期阶段(除了回复视图)之后调用该措施。

3、UI标签的使用举例:

3.1、<h:form>和着力输入标签的采取:

<f:view>
    <h1>表单标签</h1>
    <h:form>
        单行文本框:<h:inputText value="#{userbean.username }" /><br />
        密码框:<h:inputSecret value="#{userbean.password }" /><br />
        多行文本区:<h:inputTextarea rows="3" cols="20" /><br />
        隐藏域:<h:inputHidden value="#{userbean.message }" /><br />
    </h:form>
</f:view>

其间<h:inputText>和<h:inputSecret>可以指定一个size属性用于指定输入框的最大尺寸。

3.2、多选标签的利用:

<h1>多选标签的使用</h1>
<h:form>
    <!-- 复选框 -->
    <h:selectManyCheckbox value="#{userbean.booklist }">
        <f:selectItem itemLabel="Core Java" itemValue="Java" />
        <f:selectItem itemLabel="Thinking in C++" itemValue="C++" />
        <f:selectItem itemLabel="Spring Internals" itemValue="Spring" />
    </h:selectManyCheckbox>

    <!-- 生成一个允许多选的列表框 -->
    <h:selectManyListbox value="#{userbean.booklist }" size="5">
        <f:selectItem itemLabel="Core Java" itemValue="Java" />
        <f:selectItem itemLabel="Thinking in C++" itemValue="C++" />
        <f:selectItem itemLabel="Spring Internals" itemValue="Spring" />
    </h:selectManyListbox>

    <!-- 生成一个允许多选的复合框 -->
    <h:selectManyMenu value="#{userbean.booklist }">
        <f:selectItem itemLabel="Core Java" itemValue="Java" />
        <f:selectItem itemLabel="Thinking in C++" itemValue="C++" />
        <f:selectItem itemLabel="Spring Internals" itemValue="Spring" />
    </h:selectManyMenu>
</h:form>

行使方面的三个标签必须与<f:selectItem>或者<f:selectItems>标签结合使用,其中的<f:selectItem>3个特性的含义:

itemLabel:可视化标签值
itemValue:指定生成列表项或者复选框的值
value:与其他的UI标签的value属性分裂,不是将该零件的值绑定到托管Bean,而是将该零件本身绑定到托管Bean

那多少个标签的value属性值必须是一个List或者数组。

3.3、单选标签的运用:

<h1>单选标签的使用</h1>
<h:form>
    <!-- 生成一组单选按钮 -->
    <h:selectOneRadio value="userbean.booklist">
        <f:selectItem itemLabel="Core Java" itemValue="Java" />
        <f:selectItem itemLabel="Thinking in C++" itemValue="C++" />
        <f:selectItem itemLabel="Spring Internals" itemValue="Spring" />
    </h:selectOneRadio>
    <!-- 生成一个只允许单选的列表框 -->
    <h:selectOneListbox value="userbean.booklist" size="5">
        <f:selectItem itemLabel="Core Java" itemValue="Java" />
        <f:selectItem itemLabel="Thinking in C++" itemValue="C++" />
        <f:selectItem itemLabel="Spring Internals" itemValue="Spring" />
    </h:selectOneListbox>
    <!-- 生成一个只允许单选的下来菜单 -->
    <h:selectOneMenu value="#{userbean.booklist }">
        <f:selectItem itemLabel="Core Java" itemValue="Java" />
        <f:selectItem itemLabel="Thinking in C++" itemValue="C++" />
        <f:selectItem itemLabel="Spring Internals" itemValue="Spring" />
    </h:selectOneMenu>
</h:form>

那多个标签和眼前介绍的五个标签的效力宗旨相似,只是那里的只好单选。

3.4、UISelectBoolean组件的接纳:

<h:selectBooleanCheckbox />

在页面上生成一个复选框,用于勾选或者废除勾选该复选框

与地点三个复选框差异,它的value属性必须绑定到托管Bean中boolean类型的质量,不须要与<f:selectItem>标签一起行使。

3.5、UICommand组件的运用:

<h1>UICommand组件的使用</h1>
<h:form>
    <!-- 生成一个可以提交表单的按钮 -->
    <h:commandButton value="点击" />
    <!-- 生成一个图片按钮 -->
    <h:commandButton image="images/01.jpg" />
    <!-- 生成一个可以提交表单的超链接 -->
    <h:commandLink value="提交表单" />
    <!-- 生成一个可以提交表单的图片链接 -->
    <h:commandLink shape="circle" coords="20,20,10">
        <img src="images/01.jpg" />
    </h:commandLink>
</h:form>

3.6、UIOutput对应的出口组件的选拔:

<h1>UIOutput对应的输出组件的使用</h1>
<!-- 使用outputText标签输出国际化资源 -->
<h:outputText value="#{userInfo.username }" />
<!-- 使用outputText标签输出Bean属性 -->
<h:outputText value="#{userbean.username }" />
<!-- 生成Label标签 -->
<h:outputLabel value="#{userbean.username }" />
<!-- 生成超链接 -->
<h:outputLink value="http://www.itzhai.com">IT宅</h:outputLink>
<!-- 输出带占位符的国际化消息 -->
<h:outputFormat value="#{userInfo.message }">
    <f:param value="arthinking" />
</h:outputFormat>

此地运用到了国际化资源,要求创设:

在faces-config.xml问价中加载国际化资源的布置:

<application>
    <resource-bundle>
        <base-name>com.itzhai.user</base-name>
        <var>userInfo</var>
    </resource-bundle>
</application>

接下来在com.itzhai目录下创办一个国际化资源文件的basename为user:

username="arthinking"
message=用户名:{0}

3.7、panelGrid和panelGroup的使用:

<h1>panelGrid标签的使用</h1>
    <h:panelGrid columns="3" width="300px" border="1">
        <!-- 生成表格标题 -->
        <f:facet name="caption">
            <h:outputText value="表格标题" />
        </f:facet>
        <!-- 生成表格头 -->
        <f:facet name="header">
            <h:outputText value="表格头" />
        </f:facet>
        <h:outputText value="1" />
        <h:outputText value="2" />
        <h:outputText value="3" />
        <!-- panelGroup的使用 -->
        <h:panelGroup layout="block" style="color:#cfcfff">
            <h:outputText value="4" />
            <h:outputText value="5" />
        </h:panelGroup>
        <h:outputText value="6" />
        <h:outputText value="7" />
    </h:panelGrid>

panelGrid用于转移表格,panelGroup用于把多少个要素结合一个元素。

3.8、使用UIData迭代输出从数额源中获取的数目:

<h1>dataTable的使用</h1>
<h:dataTable width="600px" border="1" value="showbook.bookList" var="book" rowClasses="odd,even">

    <!-- 使用facet生成caption -->
    <f:facet name="caption">
        <h:outputText value="book list" />
    </f:facet>

    <!-- 定义第一列 -->
    <h:column>
        <f:facet name="header">
            <h:outputText>图书名</h:outputText>
        </f:facet>
        <h:inputText value="#{book.name }" size="3" />
    </h:column>
    <!-- 定义第二列 -->
    <h:column>
        <f:facet name="header">
            <h:outputText>图书分类</h:outputText>
        </f:facet>
        <h:outputLink value="#{book.url }">
            <h:inputText value="#{book.bookClass }" />
        </h:outputLink>
    </h:column>

    <!-- 生成表格底部 -->
    <f:facet name="footer">
        <h:panelGroup>
            <h:outputText value="计算机书籍" />
        </h:panelGroup>
    </f:facet>
</h:dataTable>

上边须求在名为showbook的托管Bean中提供一个bookList数据源,可以在她的get方法中提供数据:

public List<BookInfo> getBookList(){
    List<BookInfo> books = new ArrayList<BookInfo>();
    books.add(new BookInfo("Core Java", "Java", "www.itzhai.com"));
    books.add(new BookInfo("Core Java", "Java", "www.itzhai.com"));
    books.add(new BookInfo("Core Java", "Java", "www.itzhai.com"));
    return books;
}

其中的BookInfo类如下:

public class BookInfo {

    private String name;
    private String url;
    private String bookClass;

    public BookInfo(String name, String bookClass, String url){
        this.name = name;
        this.bookClass = bookClass;
        this.url = url;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getBookClass() {
        return bookClass;
    }
    public void setBookClass(String bookClass) {
        this.bookClass = bookClass;
    }
}

3.9、图像组件的拔取:

<h:graphicImage value="images/01.jpg" alt="图像01" />

这几个标签将生成HTML的img标签。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图