并行编程下的选择

原创
2015/01/18 19:29
阅读数 1K

       最近在看一些游戏群里面都在讨论actor,以前还真没接触过,赶紧了解一下。
       感觉最经典的总结就是那句:万物皆Actor。Actor之间只有发送消息这一种通信方式,消息让Actor之间解耦;Actor模型的消息传递形式简化了并行程序的开发。自己做的2个游戏项目都用了不同的并发处理模型,在此做一个总结。
      1.actor模式
       java平台目前还不支持actor,但并不影响我们使用actor,目前已经有多种支持actor的库,如akka,μJavaActors 库,这是一个轻型的、基于 Java 的 actor 包,用于在传统 Java 应用程序中实现高度并行的执行。
这里打算用μJavaActors 库做一个简单的实例。
具体μJavaActors 库参考:http://www.ibm.com/developerworks/cn/java/j-javaactors/#resources

public class GamePlayerActor extends AbstractActor {
	private int gold;// 玩家金币

	@Override
	protected void loopBody(Message arg0) {
		String subject = arg0.getSubject();
		if (!subject.equals("init")) {
			int count = (Integer) arg0.getData();
			setGold(getGold() + count);
			System.out.println(subject + ",金币+" + count + ",总金币=" + getGold());
		}
	}
       //省略get/set...
}
玩家actor,接受各种类型的金币获取

public class ResourceActor extends AbstractActor {
	private Actor sendTo;

	@Override
	protected void runBody() {
		DefaultMessage m = new DefaultMessage("资源收获", 50);
		getManager().send(m, this, sendTo);
	}
	@Override
	protected void loopBody(Message arg0) {

	}
	public void setSendTo(Actor sendTo) {
		this.sendTo = sendTo;
	}
}
资源actor,获取金币的途径,相信玩过一下策略类游戏的都知道有收获资源。

public class RewardActor extends AbstractActor {

	private Actor sendTo;

	@Override
	protected void runBody() {
		DefaultMessage m = new DefaultMessage("奖励", 100);
		getManager().send(m, this, sendTo);
	}
	@Override
	protected void loopBody(Message arg0) {

	}
	public void setSendTo(Actor sendTo) {
		this.sendTo = sendTo;
	}
}

奖励actor, 获取金币的途径,发送奖励获得金币。

下面是一个测试类:

public class Main {
	public static void main(String[] args) {
		final DefaultActorManager am = new DefaultActorManager();
		try {
			Map<String, Object> options = new HashMap<String, Object>();
			options.put(DefaultActorManager.ACTOR_THREAD_COUNT, 20);
			am.initialize(options);

			final GamePlayerActor gamePlayerActor = (GamePlayerActor) am
					.createActor(GamePlayerActor.class, "gamePlayerActor");
			// 接受消息actor
			am.startActor(gamePlayerActor);
			for (int i = 0; i < 10; i++) {
				final int k = i;
				new Thread(new Runnable() {
					@Override
					public void run() {
						ResourceActor a = (ResourceActor) am.createActor(
								ResourceActor.class, "a" + k);
						RewardActor b = (RewardActor) am.createActor(
								RewardActor.class, "b" + k);
						a.setSendTo(gamePlayerActor);
						b.setSendTo(gamePlayerActor);

						// 发送消息actor
						am.startActor(a);
						am.startActor(b);
					}
				}).start();
			}

			Thread.sleep(100000);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
结果:(预期结果是1500,实际结果也是1500)
资源收获,金币+50,总金币=50
资源收获,金币+50,总金币=100
资源收获,金币+50,总金币=150
奖励,金币+100,总金币=250
奖励,金币+100,总金币=350
资源收获,金币+50,总金币=400
资源收获,金币+50,总金币=450
奖励,金币+100,总金币=550
奖励,金币+100,总金币=650
资源收获,金币+50,总金币=700
资源收获,金币+50,总金币=750
奖励,金币+100,总金币=850
奖励,金币+100,总金币=950
奖励,金币+100,总金币=1050
奖励,金币+100,总金币=1150
资源收获,金币+50,总金币=1200
资源收获,金币+50,总金币=1250
资源收获,金币+50,总金币=1300
奖励,金币+100,总金币=1400
奖励,金币+100,总金币=1500
        2.大家最熟悉的java并发处理
       synchronized 代码块、wait/notify 和 java.util.concurrent 包等关键字,刚开始做第一个游戏的时候,就使用的这种方式。整个游戏只有一个vm,我们通过封装了一下ehcache,将玩家的信息都保存在本地内存中,玩家的每一块信息在内存中都只存在一份,比如gameplayer,在内存中只存在一个对象 gameplayer,整个代码中都是这种模式:
public class GamePlayer {

	private int glod;

	public synchronized void addGold(int count) {
		this.glod += count;
	}
       //略...
}

      3.队列模式
     
这种模式也是当前游戏中正在使用的,给每个玩家一个消息队列,对某一个玩家来讲,其实都是一个单线程。

private OrderedQueuePoolExecutor recvExcutor = new OrderedQueuePoolExecutor(
			"消息接收队列", 100, 10000);

@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
			throws Exception {
	Message request = (Message) e.getMessage();
	recvExcutor.addTask(request.getHeader().getSessionid(), new MWork(
				request, e.getChannel()));
}

OrderedQueuePoolExecutor 是一个有序的队列线程池(这里代码就不贴了),这里其实就是用每个玩家的session关联一个消息队列,其实有点想actor模式。

总结:actor应该是一种很好的模式,而且也提供了一些成熟的框架,但是使用Actor模型编写应用程序,需要开发人员使用一种与以往不同的设计思路,这样的思路说难倒不难,说简单也不简单。第三种队列模式我觉得更加简单。


展开阅读全文
加载中
点击加入讨论🔥(6) 发布并加入讨论🔥
6 评论
13 收藏
1
分享
返回顶部
顶部