你们能告诉我一种在Google App Engine上模拟对memcache的并发访问的方法吗?我正在尝试使用LocalServiceTestHelpers和线程,但没有任何运气。每次我尝试在线程中访问Memcache时,我都会收到此错误:
ApiProxy$CallNotFoundException: The API package 'memcache' or call 'Increment()' was not found
我猜GAE SDK的测试库试图模仿真实环境,因此只为一个线程(运行测试的线程)设置环境,这是其他线程无法看到的。
这是一段可以重现问题的代码
package org.seamoo.cache.memcacheImpl;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.google.appengine.tools.development.testing.LocalMemcacheServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
public class MemcacheTest {
LocalServiceTestHelper helper;
public MemcacheTest() {
LocalMemcacheServiceTestConfig memcacheConfig = new LocalMemcacheServiceTestConfig();
helper = new LocalServiceTestHelper(memcacheConfig);
}
/**
*
*/
@BeforeMethod
public void setUp() {
helper.setUp();
}
/**
* @see LocalServiceTest#tearDown()
*/
@AfterMethod
public void tearDown() {
helper.tearDown();
}
@Test
public void memcacheConcurrentAccess() throws InterruptedException {
final MemcacheService service = MemcacheServiceFactory.getMemcacheService();
Runnable runner = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
service.increment("test-key", 1L, 1L);
try {
Thread.sleep(200L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
service.increment("test-key", 1L, 1L);
}
};
Thread t1 = new Thread(runner);
Thread t2 = new Thread(runner);
t1.start();
t2.start();
while (t1.isAlive()) {
Thread.sleep(100L);
}
Assert.assertEquals((Long) (service.get("test-key")), new Long(4L));
}
}
答案 0 :(得分:5)
您是否正在尝试测试您的应用或App Engine的memcache实施?并发读写下的memcache的语义很好理解 - 你最好简单地模拟可能发生的条件,以验证你的应用处理它们。
答案 1 :(得分:2)
问题是如何设置线程,并且可以使用SDK中提供的ThreadManager来解决:
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
@Before
public void setUp() throws Exception {
helper.setUp();
}
@After
public void tearDown() throws Exception {
helper.tearDown();
}
AtomicInteger threadsRemaining = new AtomicInteger(NUM_USERS);
AtomicInteger numFailingThreads = new AtomicInteger(0);
@Test
public void testManyUsers() throws Exception {
ArrayList<TestUser> testUsers = new ArrayList<TestUser>();
// Create something to test in parallel (in this case a "user")
for (int i = 0; i < NUM_USERS; ++i) {
testUsers.add(new TestUser());
}
// Fork off a thread for each user
runInParallel(testUsers);
// Wait for threads to complete.
while (threadsRemaining.intValue() != 0) {
Thread.sleep(10); // TODO: Clean up with callbacks or whatever.
}
assertEquals(numFailingThreads.intValue(), 0);
}
private void runInParallel(final ArrayList<TestUser> testUsers) {
for (final TestUser u : testUsers) {
Runnable myTask = new Runnable() {
@Override
public void run() {
try {
// The user tries to kill my server
} catch (Exception e) {
// The user triggered badness in my server
e.printStackTrace();
numFailingThreads.incrementAndGet();
}
threadsRemaining.decrementAndGet();
}
};
ThreadFactory threadFactory = ThreadManager.currentRequestThreadFactory();
Thread t = threadFactory.newThread(myTask);
t.start();
}
}
答案 2 :(得分:1)
GAE不支持用户线程。我认为你试图过度复杂化。
您可以测试这种方法的一种方法是创建一个外部Threaded客户端,并生成尽可能多的线程,以便远程访问GAE。如果它在你的本地盒子上运行就指向那里。
答案 3 :(得分:0)
我猜是测试库的 GAE SDK试图模仿真实 环境,从而设置 只有一个线程的环境( 运行测试的线程) 其他线程无法看到。
这个猜测大致正确:因为GAE本身从不在一个进程中运行多个线程,因此SDK也没有 - 所以我不清楚为什么要测试GAE中不会发生的多线程访问