续:队列的应用 之 M/D/1队列

模拟:

        MD1Queue 是 Queue 客户端 ,你可能使用它来验证这类数学结果。他是基于事件模拟的简单示例:我们产生的事件发生在特定时间,为了事件相应的调整我们的数据结构,模拟当事件出现时,发生了什么。在M/D/1队列中,有两类事件:不是有顾客到达,就是提供顾客服务,因此我们需要维护两个变量:


            · nextService 是下一个服务的时间
   · nextArrival   是下一个到达的时间


        为了模拟到达事件,在队列中插入double值,nextvalArrival是到达时间;为了模拟服务,中队列中删除值,计算等待时间(离开队列时间减去服务时间nextService是到达时间)并将等待时间数据点加到直方图上(直方图程序Histogram)。在多次试验之后,结果的形状是M/D/1排队系统的特性。从实用观点来看,这个过程中的一个最重要特征是,通过使用不同的λ和μ值运行MD1Queue,你会发现当服务率逼近到达率时,平均等待时间和队列长度可能剧增。当服务费率很高时,直方图有一个可见的尾部,此时随着等待时间的减少,顾客需要等待时间的频率减少到几乎可以忽略不计。但是,当服务费率逼近到达率时,直方图的尾部在最多值处伸展,因此至少能显示顾客最长等待时间频率。

/*************************************************************************
 *  Compilation:  javac MD1Queue.java
 *  Execution:    java MD1Queue lambda mu
 *  Dependencies: Queue.java
 *
 *  % java MD1Queue .167 .25
 *
 *  % java MD1Queue .167 .22
 * 
 *************************************************************************/

public class MD1Queue { 

    public static void main(String[] args) { 
        double lambda = Double.parseDouble(args[0]);   // arrival rate
        double mu     = Double.parseDouble(args[1]);   // service rate

        Histogram hist = new Histogram(60 + 1);
        Queue<Double> queue = new Queue<Double>();
        StdDraw.setCanvasSize(700, 500);

        double nextArrival = StdRandom.exp(lambda);    // time of next arrival
        double nextService = nextArrival + 1/mu;       // time of next completed service

        while (true) {

            // next event is an arrival
            while (nextArrival < nextService) {
                queue.enqueue(nextArrival);
                nextArrival += StdRandom.exp(lambda);
            } 

            // next event is a service completion
            double arrival = queue.dequeue();
            double wait = nextService - arrival;

            // update the histogram
            StdDraw.clear();
            hist.addDataPoint(Math.min(60,  (int) (Math.round(wait))));
            hist.draw();
            StdDraw.show(20);

            // update the queue
            if (queue.isEmpty()) nextService = nextArrival + 1/mu;
            else                 nextService = nextService + 1/mu;
        } 
    } 
} 

public class Histogram {
    private final double[] freq;   // freq[i] = # occurences of value i
    private double max;            // max frequency of any value

    public Histogram(int N) {
        freq = new double[N];
    }

    // Add one occurrence of the value i. 
    public void addDataPoint(int i) {
        freq[i]++; 
        if (freq[i] > max) max = freq[i]; 
    } 

    // draw (and scale) the histogram.
    public void draw() {
        StdDraw.setYscale(0, max);
        StdStats.plotBars(freq);
    }
 
    public static void main(String[] args) {
        int N = Integer.parseInt(args[0]);   // number of coins
        int T = Integer.parseInt(args[1]);   // number of trials

        // create the histogram
        Histogram histogram = new Histogram(N+1); 
        for (int t = 0; t < T; t++) {
            histogram.addDataPoint(Bernoulli.binomial(N));
        }

        // display using standard draw
        StdDraw.setCanvasSize(500, 100);
        histogram.draw();
    } 
} 

import java.util.Iterator;
import java.util.NoSuchElementException;

public class Queue<Item> implements Iterable<Item>
{
	private int N; // number of elements on queue
	private Node first; // beginning of queue
	private Node last; // end of queue

	private class Node
	{
		private Item item;
		private Node next;
	}

	public Queue()
	{
		first = null;
		last = null;
	}

	public boolean isEmpty()
	{
		return first == null;
	}

	public int length()
	{
		return N;
	}

	public void enqueue(Item item)
	{
		Node x = new Node();
		x.item = item;
		if (isEmpty())
		{
			first = x;
			last = x;
		}
		else
		{
			last.next = x;
			last = x;
		}
		N++;
	}

	// remove and return the least recently added item
	public Item dequeue()
	{
		if (isEmpty())
			throw new RuntimeException("Queue underflow");
		Item item = first.item;
		first = first.next;
		N--;
		return item;
	}

	public Iterator<Item> iterator()
	{
		return new QueueIterator();
	}

	// an iterator, doesn't implement remove() since it's optional
	private class QueueIterator implements Iterator<Item>
	{
		private Node current = first;

		public boolean hasNext()
		{
			return current != null;
		}

		public void remove()
		{
			throw new UnsupportedOperationException();
		}

		public Item next()
		{
			if (!hasNext())
				throw new NoSuchElementException();
			Item item = current.item;
			current = current.next;
			return item;
		}
	}

}


        像我们在许多其他应用中所分析的一样,使用模拟来验证还不完全理解的数学模型试验就更个复杂情况的一个起点。在队列中的实际应用中,我们可以有多个队列,多台服务器,多级服务器,限制队列大小和许多其他限制。而且,到达分布和服务时间可能不能用数学方式描述。在这写情况下,我们不可能求助于其他,只能使用模拟。我们可以更多的使用模拟来调整系统设计参数(比如:服务率)来适当反映外部的环境(比如:到达率)。


2011年7月7日02:30稿。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MQ服务器端和客户端通信浅谈 1. WebSphere MQ的服务端的安装和配置 (1)创建名为venus.queue.manager的默认队列管理器。 在DOS窗口命令提示符下,输入以下命令: crtmqm -q venus.queue.manager (2)启动刚才创建的队列管理器。 在DOS窗口命令提示符下,输入以下命令: strmqm venus.queue.manager (3)启动MQSC命令。 在DOS窗口命令提示符下,输入以下命令: runmqsc venus.queue.manager (4)新建名为orange.queue的本地队列。 输入以下命令: define qlocal (orange.queue) 注意:MQSC中任何小写字母将自动转换成大写,除非用单引号将它们括起来。这意味着如果使用名称Orange.Queue创建了队列,则记住在MQSC以外其他命令中都必须使用Orange.Queue。 (5)停止MQSC。 输入以下命令: end 现在,我们已经定义了以下对象: (1)名为venus.queue.manager的默认队列管理器。 (2)名为ORANGE.QUEUE的队列。 测试对象:要测试队列管理器和队列,请使用样本程序amqsput(将消息放入队列)和amqsget(从队列获取消息),步骤如下: (1)启动DOS窗口,进入到C:\Program Files\IBM\WebSphere MQ\bin目录下。 (2)将消息放入队列。 输入以下命令: amqsput ORANGE.QUEUE 显示以下消息: Sample amqsput0 start Target queue is ORANGE.QUEUE (3)输入一些字符数据,然后双击"Enter"键,则显示以下消息: Sample amqsput0 end 现在消息已经被放在队列中了。 (4)要从队列中获取消息,输入以下命令: amqsget ORANGE.QUEUE 在屏幕上将显示您刚才输入的字符数据消息。暂停后,例子程序结束。 如果以上步骤都能完成,则完成了本地安装的验证。 注意:如果在任何阶段中断整个安装过程,则应该从头开始重新运行安装。 2. WebSphere MQ客户端的安装和配置 如果我们开发的基于MQ的应用与MQ服务器不在同一台机器上,那么就必须在MQ应用端安装MQ客户端。下面我们以在Suse Linux 10下安装WebSphere MQ v6.0 Client为例介绍MQ客户端在Linux下的安装和配置步骤。 (1)解压缩MQ客户端安装包:C84CJML.WebSphere MQ V6.0 Linux x86 Client.tar.gz,命令如下: tar -xvfz C84CJML.WebSphere MQ V6.0 Linux x86 Client.tar.gz (2)创建WebSphere MQ 必需的文件系统,命令如下: mkdir /opt/mqm # for product code mkdir /var/mqm # for working data (3)创造MQ用户和用户组,命令如下: groupadd mqm useradd -d /var/mqm -g mqm -G mqm mqm passwd mqm # change password to "password" (4)为mqm用户组添加root组 cd /etc vi group 修改 mqm:!:1000:mqm ? mqm:!:1000:mqm,root (5)调整系统参数(视需要而定) 修改最大共享内存,命令如下: cat /proc/sys/kernel/shmmax echo 268435456 >/proc/sys/kernel/shmmax 修改最大文件句柄,命令如下: cat /proc/sys/fs/file-max echo 32768 >/proc/sys/fs/file-max (6)转到WebSphere MQ解压后的目录中,获得WebSphere MQ授权,命令如下: ./mqlicense.sh -text_only 阅读全文后,选择1接受授权。 (7)安装WebSphere MQ客户端,命令如下: rpm -ivh MQSeriesRuntime-6.0.0-0.i386.rpm rpm -ivh MQSeriesSDK-6.0.0-0.i386.rpm rpm -ivh MQSeriesJava-6.0.0-0.i386.rpm rpm -ivh MQSeriesClient-6.0.0-0.i386.rpm rpm -ivh MQSeriesSamples-6.0.0-0.i386.rpm (8)安装校验 rpm -qa | grep MQSeries 结果如下则表明MQ 客户端的安装已成功。 MQSeriesRuntime-6.0.0-0 MQSeriesSDK-6.0.0-0 MQSeriesJava-6.0.0-0 MQSeriesClient-6.0.0-0 MQSeriesSamples-6.0.0-0 3. WebSphere MQ的服务端和客户端的互联 本节的WebSphere MQ的服务端和客户端不在同一台机器上。 本节以上述1,2两个步骤安装好的MQ服务端和MQ客户端为例,介绍如何配置MQ的服务端和客户端使两者能够互联。 (1)服务端配置 1)点"开始"->"所有程序"->"IBM WebSphere MQ"->"WebSphere MQ 资源管理器",进入WebSphere MQ 资源管理器界面。如下图所示: 2)创建名为"QM_JACK"的队列管理器 选中"队列管理器"->"新建"->"队列管理器",如下图所示: 在队列管理中输入"QM_JACK",其他选项默认不变,点"下一步": 设置队列日志(本步骤采用系统默认设置),点"下一步": 启动队列管理器,创建服务器连接通道,允许在TCP/IP上进行队列管理器的远程管理,点击"下一步": 设置队列管理器QM_JACK的侦听端口:8927(用户可以根据需要自行更改端口号),点击"完成"。 系统进入等待界面: 队列管理器QM_JACK创建成功 3)在QM_JACK下创建名为"QUEUE_RECV"和"QUEUE_REPLY"的本地队列(客户可以根据自己的需求随意更改本地队列的名字和数量,这里创建这两个本地队列只是为之后的MQ_Tuxedo项目作准备): 设置队列名后其他属性全为系统默认值,点击"确定"。 4)在QM_JACK下创建名为"CNN_JACK"的服务器通道。 通道名称设为CNN_JACK,其他选项保留为系统默认设置,点击"确定"。 5)在MQ服务器端的计算机用户中添加MQ客户端所在计算机的系统用户。比如我的MQ客户端被Suse Linux下的root用户使用,那么,我们就需要在MQ的服务端(也就是Windows xp系统中添加名为"root"的用户)所在的计算机系统中添加名为"root"的用户。具体步骤如下: 点击"开始"->"控制面板"->"计算机管理"->"系统工具"->"本地用户和组"->"用户",点右键,选"新用户",如下图所示: 创建新用户:root(注意:这里的用户名"root"是MQ客户端所在系统的用户名,用户要根据具体情况进行修改) 随意设置一个有效密码,选中密码永不过期,点击"创建"。 将新用户加入mqm组(注意:这里的mqm组是我们安装完MQ Server后系统自动创建的) 启动监听器 Runmqlsr –m QM_JACK" 设置 export MQCHLTAB= /PTAH/AMQCLCHL.TAB 重启机器。至此,MQ服务端的配置完成。 (2)客户端配置 按照我们前面的步骤,MQ客户端是安装在Suse Linux 10 上,所以本节以Suse Linux 10下的MQ Client v6为例说明如何配置MQ客户端才能连上MQ服务器。 1)设置MQSERVER环境变量,命令如下: export MQSERVER='CNN_JACK/tcp/9.186.110.133(8927)' 参数说明: 服务器连接通道名称:CNN_JACK 服务器连接通道协议类型:tcp 服务器IP地址:9.186.110.133 服务器连接通道所在的队列管理器QM_JACK的侦听端口:8927 2)测试客户端与服务端的网络连接 在客户端使用ping命令检查客户端是否能连上服务端机器。 同样,在服务端使用ping命令检查服务端是否能连上客户端机器。 测试完成后,进入下一步。 3)进入/opt/mqm/samp/bin,使用样本程序amqsputc(用来将消息发送到服务端队列)和amqsgetc(用来从服务端队列中读取消息)来测试客户端与服务端的MQ连接是否畅通,具体步骤如下: 输入命令: ./amqsputc QUEUE_RECV QM_JACK 则会显示以下消息: Sample AMQSPUT0 start target queue is QUEUE_RECV 输入一些字符,然后双击"Enter"键,则显示如下信息: Sample AMQSPUT0 end 要从队列获取消息,则输入如下命令: ./amqsgetc QUEUE_RECV QM_JACK 则会在屏幕上打印出刚才输入的字符数据消息。暂停后,;例子程序结束。 如果以上步骤都能够完成,则完成了MQ服务端和客户端的互联配置。 注意:有时候,MQ客户端联服务端时会因为两端字符集编码CCSID不一样造成连接的失败,典型错误是:MQCONN ended with reason code 2059。在队列管理器的错误日志(位于/var/mqm/errors/AMQERROR**.log)中有如下信息: ------------------------------------------------------------------------------- 08/23/2002 11:51:48 AMQ9541: CCSID supplied for data conversion not supported. EXPLANATION: The program ended because, either the source CCSID '437' or the target CCSID '1381' is not valid, or is not currently supported. ACTION: Correct the CCSID that is not valid, or ensure that the requested CCSID can be supported. 解决方法如下:在服务端用runmqsc qmname命令,输入dis qmgr查看CCSID属性值nnnn,在客户端上配置环境变量: Windows 下:set MQCCSID=nnnn(在服务端看到的CCSID), Linux下:export MQCCSID=nnnn(在服务端看到的CCSID),重新启动MQ 客户端机器即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值